6

Pop-11からPythonと同等のpdtolistを作成するにはどうすればよいですか?

(たとえば)整数を一度に1つずつ返すgというジェネレーターがあるとします。リストの現在の終わりを超える値を要求すると、自動的に大きくなるリストを作成したいと思います。例えば:

print a # => [ 0, 1, 2, g]
print a[0] # => 0
print a[1] # => 1
print a[2] # => 2
# (obvious enough up to here)

print a[6] # => 6
print a # => [ 0, 1, 2, 3, 4, 5, 6, g]
# list has automatically expanded

a = a[4:] # discard some previous values
print a # => [ 4, 5, 6, g]
print a[0] # => 4

用語-誤解の可能性を予測するために:リストは「動的配列」ですが、それは私が意味することではありません。もっと抽象的な意味での「ダイナミックリスト」が欲しいのですが。

動機をよりよく説明するために、処理する999999999アイテムがあるとします。それらすべてを(通常のリストの)メモリに一度に収めようとするのは難しいでしょう。ジェネレーターは、問題のその部分を一度に1つずつ提示することで解決します。それぞれがオンデマンドで作成されるか、ディスクから個別に読み取られます。しかし、処理中に、現在の値だけでなく、最近の値を参照したいとしますか?別のリストにある最後の(たとえば)10個の値を思い出すことができます。ただし、動的リストは自動的に記憶されるため、より優れています。

4

4 に答える 4

2

アイデアを提供してくれたすべての人に感謝します!これが私がすべての回答から集めたものです。これにより、通常のリストクラスのほとんどの機能が保持され、追加の要件を満たすために必要な場合に追加の動作が追加されます。

class DynamicList(list):
    def __init__(self, gen):
        self.gen = gen

    def __getitem__(self, index):
        while index >= len(self):
            self.append(next(self.gen))
        return super(DynamicList, self).__getitem__(index)

    def __getslice__(self, start, stop):
        # treat request for "last" item as "most recently fetched"
        if stop == 2147483647: stop = len(self)
        while stop >  len(self):
            self.append(next(self.gen))
        return super(DynamicList, self).__getslice__(start, stop)

    def __iter__(self):
        return self

    def next(self):
        n = next(self.gen)
        self.append(n)
        return n

a = DynamicList(iter(xrange(10)))

以前に生成された値は、アイテムまたはスライスとして個別にアクセスできます。要求されたアイテムがリストの現在の終わりを超えている場合、記録された履歴は必要に応じて拡張されます。記録された履歴全体は、を使用して一度にアクセスするprint aか、を使用して通常のリストに割り当てることができますb = a[:]。記録された履歴のスライスは、を使用して削除できますdel a[0:4]。、を使用してリスト全体を反復処理しforたり、必要に応じて削除したりできます。生成された値の最後に到達すると、が発生しますStopIteration

いくつかの厄介さが残っています。のような割り当てa = a[0:4]は、履歴を正常に切り捨てますが、結果のリストは自動拡張されなくなります。代わりdel a[0:4]に、自動成長プロパティを保持するために使用します。2147483647また、最新のアイテムを表す魔法の値を認識しなければならないことに完全に満足しているわけではありません。

于 2012-07-13T16:11:09.597 に答える
2

これはあなたを始めるかもしれません:

class DynamicList(list):
    def __init__(self, gen):
        self._gen = gen

    def __getitem__(self, index):
        while index >= len(self):
            self.append(next(self._gen))
        return super(DynamicList, self).__getitem__(index)

スライスに特別な処理を追加する必要があります (現在、スライスは通常のリストを返すだけなので、動的な動作は失われます)。また、ジェネレーター自体をリスト項目にしたい場合は、少し複雑になります。

于 2012-06-29T16:22:39.337 に答える
2

別の同様の質問に回答したところ、私の回答を更新することにしました。

class dynamic_list(list):
    def __init__(self,num_gen):
        self._num_gen = num_gen
    def __getitem__(self,index):
        if isinstance(index, int):
            self.expandfor(index)
            return super(dynamic_list,self).__getitem__(index)

        elif isinstance(index, slice):
            if index.stop<index.start:
                return super(dynamic_list,self).__getitem__(index)
            else:
                self.expandfor(index.stop if abs(index.stop)>abs(index.start) else index.start)
            return super(dynamic_list,self).__getitem__(index)

    def __setitem__(self,index,value):
        if isinstance(index, int):
            self.expandfor(index)
            return super(dynamic_list,self).__setitem__(index,value)

        elif isinstance(index, slice):
            if index.stop<index.start:
                return super(dynamic_list,self).__setitem__(index,value)
            else:
                self.expandfor(index.stop if abs(index.stop)>abs(index.start) else index.start)
            return super(dynamic_list,self).__setitem__(index,value)

    def expandfor(self,index):
            rng = []
            if abs(index)>len(self)-1:
                if index<0:
                    rng = xrange(abs(index)-len(self))
                else:
                    rng = xrange(abs(index)-len(self)+1)
            for i in rng:
                self.append(self._num_gen.next())
于 2012-06-29T16:29:10.613 に答える