2012-06-29 17 views
6

と同等のPythonを作成するにはどうすればいいですか?pdtolistはPop-11からですか?自動的に展開される動的リスト

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

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の値を思い出すことができます。しかし、動的リストは、自動的にそれらを覚えているので、より良いです。

+0

リストの '__getitem__'メソッドをオーバーライドして' IndexError'をキャッチします。 –

+0

あなたは 'L'をリストし、' L [999999999] 'を実行します - そのリストはその長さになるはずですか? –

+0

はい、原則です。プログラマーに警告! –

答えて

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を認識することには全く満足していません。

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) 

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

+0

これはリストサブクラスであってはなりません。 '__init__'は互換性がなく、' __len__'や '__setitem__'をサポートしてはいけません... – agf

+0

@agf:' __init__'問題は有効な点ですが、 '__len__'や' __setitem__'をサポートしないのはなぜですか? – voithos

+0

ジェネレータの長さは不明で、ジェネレータのアイテムのみを反映する必要があるため、長さは不明です。ジェネレータの長さは不明です。 – agf

1

ちょうど別の同様の質問に回答し、私の回答を更新することにしました これはどうですか?

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()) 
関連する問題