2016-04-13 5 views
1

非常に大きい(ギガバイト)任意のオブジェクトのリストが与えられています(私はこれと同じような解決法をintに見ました)、等価でサブリストに簡単にグループ化できますか?インプレースまたは元のリストを消費するジェネレータのいずれか。どのようにオブジェクトのリストを連続性でグループ化できますか?

l0 = [A,B, A,B,B, A,B,B,B,B, A, A, A,B] #spaces for clarity 

望ましい結果は:

for g in gen(l0): 
    print g 
.... 
['A', 'B'] 
['A', 'B', 'B'] 
['A', 'B', 'B', 'B', 'B'] 
.... 
:これは同じように動作しますジェネレータ gen0(l)として行うことができます

#find boundaries 
b0 = [] 
prev = A 
group = A 
for idx, elem in enumerate(l0): 
    if elem == group: 
     b0.append(idx) 
    prev = elem 
b0.append(len(l0)-1) 

for idx, b in enumerate(b0): 
    try: 
     c = b0[idx+1] 
    except: 
     break 
    if c == len(l0)-1: 
     l1.append(l0[b:]) 
    else: 
     l1.append(l0[b:c]) 

[['A', 'B'], ['A', 'B', 'B'], ['A', 'B', 'B', 'B', 'B'], ['A'], ['A'], ['A', 'B']] 

は、私はそうのようなループバージョンを書きました

など?

EDIT:パイソン2.6または2.7

EDITを使用して:好適な溶液、ほとんど受け入れ答えに基づく:

def gen_group(f, items): 
    out = [items[0]] 
    while items: 
     for elem in items[1:]: 
      if f(elem, out[0]): 
       break 
      else: 
       out.append(elem) 

     for _i in out: 
      items.pop(0) 
     yield out 
     if items: 
      out = [items[0]] 

g = gen_group(lambda x, y: x == y, l0) 

for out in g: 
    print out 
+0

したがって、各サブリストが最初の要素として "A"で始まり、この単一の "A"要素のみを含むようにリストをサブリストに分割しますか? –

+0

いいえ、それぞれのサブリストには最初のAだけが必要ですが、後には多くのBが必要です。 – jambox

+0

リストが「A」で始まることは安全な仮定ですか? –

答えて

1

は、あなたのタスクを実行するための簡単なジェネレータです:

def gen_group(L): 
    DELIMETER = "A" 
    out = [DELIMETER] 
    while L: 
     for ind, elem in enumerate(L[1:]): 
      if elem == DELIMETER : 
       break 
      else: 
       out.append(elem) 

     for i in range(ind + 1): 
      L.pop(0) 

     yield out 
     out = [DELIMETER ] 

アイデアがリストを削減し、何も残っがなくなるまでのサブリストを得ることです。これは、リストが "A"(DELIMETER変数)で始まると仮定します。

サンプル出力:sコードの複数行の文字列(ここで

timeit.timeit(s, number=100000)は、現在の回答の各々をテストするために使用されている:

for out in gen_group(l0): 
    print out 

['A', 'B'] 
['A', 'B', 'B'] 
['A', 'B', 'B', 'B', 'B'] 
['A'] 
['A'] 
['A', 'B'] 
['A'] 

Comparitiveタイミングを生成します以下に列挙する):

     Trial 1 Trial 2 Trial 3 Trial 4 | Avg 
This answer (s1):  0.08247 0.07968 0.08635 0.07133 0.07995 
Dilara Ismailova (s2): 0.77282 0.72337 0.73829 0.70574 0.73506 
John Coleman (s3):  0.08119 0.09625 0.08405 0.08419 0.08642 

この回答は最も速いですが、非常に近いです。John Colemanの答えでは、その違いが追加の議論と無名関数だと思う。

s1="""l0 = ["A","B", "A","B","B", "A","B","B","B","B", "A", "A", "A","B"] 

def gen_group(L): 
    out = ["A"] 
    while L: 
     for ind, elem in enumerate(L[1:]): 
      if elem == "A": 
       break 
      else: 
       out.append(elem) 

     for i in range(ind + 1): 
      L.pop(0) 

     yield out 
     out = ["A"] 

out =gen_group(l0)""" 

s2 = """A, B = 'A', 'B' 
x = [A,B, A,B,B, A,B,B,B,B, A, A, A,B] 
map(lambda arr: [i for i in arr[0]], map(lambda e: ['A'+e], ''.join(x).split('A')[1:]))""" 

s3 = """def subListGenerator(f,items): 
    i = 0 
    n = len(items) 
    while i < n: 
     sublist = [items[i]] 
     i += 1 
     while i < n and not f(items[i]): 
      sublist.append(items[i]) 
      i += 1 
     yield sublist 

items = ['A', 'B', 'A', 'B', 'B', 'A', 'B', 'B', 'B', 'B', 'A', 'A', 'A', 'B'] 
g = subListGenerator(lambda x: x == 'A',items)""" 

+0

良いですが、AとBは単なるプレースホルダーなので、C、Dまたは(実際には)任意のオブジェクトとなり、obj0.att1 == obj1.att1と動作するような属性を比較します。私はこれが基本的にそれだと思うが、それについて考えてみようと私に分を与える... – jambox

+0

タイミングに関しては、私はそれを本当にドローと呼ぶだろう。 – jambox

+0

@jambox、もう少し試してみることにしました。 – wnnmaw

1

この場合、次の作品。 l[0] != 'A'の条件を変更することができます。私はおそらくそれを引数として渡すので、他の場所でそれを再利用することができます。

def gen(l_arg, boundary): 
    l = l_arg.copy() # Optional if you want to save memory 
    while l: 
     sub_list = [l.pop(0)] 
     while l and l[0] != boundary: # Here boundary = 'A' 
      sub_list.append(l.pop(0)) 
     yield sub_list 

これは、リストの冒頭に'A'があることを前提としています。そしてリストをコピーします。リストがGbの範囲にあるときはそれほど大きくありません。元のリストを保持することを気にしなければ、コピーを削除してメモリを節約することができます。たぶん

+0

寒いですが、大きな入力を与えた場合、多くのメモリを使用します。 l = l_arg.copy() – jambox

+0

最後の文章を参照してください。基本的には、後にリストが必要ない場合は、関数の最初の行を削除するだけです。 – ursan

+0

OK私のせいで、私はあなたがそれを言ったことに気付かなかった。もう一つは、「A」はハードコードされていますが、私は任意のオブジェクトを言いました。だからジョンの解決策は、彼のために私は同等の機能を渡すことができるので、ポイントを取得します。 – jambox

2

このような何か:同じように使用

def subListGenerator(f,items): 
    i = 0 
    n = len(items) 
    while i < n: 
     sublist = [items[i]] 
     i += 1 
     while i < n and not f(items[i]): 
      sublist.append(items[i]) 
      i += 1 
     yield sublist 

>>> items = ['A', 'B', 'A', 'B', 'B', 'A', 'B', 'B', 'B', 'B', 'A', 'A', 'A', 'B'] 
>>> g = subListGenerator(lambda x: x == 'A',items) 
>>> for x in g: print(x) 

['A', 'B'] 
['A', 'B', 'B'] 
['A', 'B', 'B', 'B', 'B'] 
['A'] 
['A'] 
['A', 'B'] 
+1

関数を渡すことは余計なようですが、何か特別な理由はありますか? – wnnmaw

+1

@wnnmaw当初の質問は、不特定の同等の概念に基づいて、「任意のオブジェクト」をサブリストに分解することを指していました。私はそれが文字列の等価性とはほとんど関係ないが、新しいサブリストを開始するかどうかを判断するためのブール関数があると思った。明らかに、コードを変更して条件が生成器にハードワイヤード接続されるようにするのは簡単です。 –

+0

はい、これはそれです、私はそれが任意のオブジェクトで動作するようにしたので、これはその意味で優れています。 OTOH @winmawあなたが入力したリストを消費していますが、私はそれを求めました!まあ、ちょうど1つのダニを与えて...厄介です。 – jambox

2

私はAがあなたのブレークポイントであることを前提としています。ここで

>>> A, B = 'A', 'B' 
>>> x = [A,B, A,B,B, A,B,B,B,B, A, A, A,B] 
>>> map(lambda arr: [i for i in arr[0]], map(lambda e: ['A'+e], ''.join(x).split('A')[1:])) 
[['A', 'B'], ['A', 'B', 'B'], ['A', 'B', 'B', 'B', 'B'], ['A'], ['A'], ['A', 'B']] 
+1

はたくさんのメモリを使いますが、良いライナーです:) – marmeladze

+0

合意された素晴らしいライナーですが、私はマルチギガバイトのリストに参加できません: – jambox

+1

私の謙虚な意見では、その1つのライナー物事を理解するのが難しくなる... –

関連する問題