2016-11-23 1 views
2

私はタプルのリストを持っており、タプルのいくつかは、タプルの最初の項目として「開始」と「終了」を持っています。私はタプルのリストをタプルのリストにバケットしたいと思います。タプルのリストには、最初の項目の「開始」と最初の項目の「終了」のタプルの間に入るかどうかによってサブリストがグループ化されます。特定のテキスト条件に基づいてタプルのリストをグループ化/バケット化する方法はありますか?

list = [('start',1),('item_1',4),('item_2',2),('end',1),('start',10),('item_1',5),('item_3',2),('end',1),('start',10),('item_1',5),('item_3',2),('item_3',9),('end',1)]] 

desired_result = [[('start',1),('item_1',4),('item_2',2),('end',1)],[('start',10),('item_1',5),('item_3',2),('end',1)],[('start',10),('item_1',5),('item_3',9),('item_3',2),('end',1)]] 

私はほとんど成功しGROUPBYとitemgetterを利用しようとしていないよ:

from operator import itemgetter 
from itertools import groupby 

[list(group) for key, group in itertools.groupby(sorted(list), itemgetter('start','end')] 

答えて

1

このため、モジュールのための余分な不要に。

"end"の後に "start"があると仮定して、 "end"を探す必要はありません。

はちょうど最後のリストに含まれるように、最後の要素のための特別なケースでスライスを使用してサブリストを構築し、その後"start"

indexes = [i for i,e in enumerate(lst) if e[0]=='start'] 

を含むアイテムのインデックスを計算する

result = [lst[indexes[i]:indexes[i+1] if i<len(indexes)-1 else len(lst)] for i in range(len(indexes))] 

結果:

[[('start', 1), ('item_1', 4), ('item_2', 2), ('end', 1)], [('start', 10), ('item_1', 5), ('item_3', 2), ('end', 1)], [('start', 10), ('item_1', 5), ('item_3', 2), ('item_3', 9), ('end', 1)]] 

商品の注文を除いてdesired_resultです私は元のリストの順序を尊重して、期待した結果のタイプミスでなければなりません。

0

itertools.groupbyはソート関数です。これであなたを助けません。おそらく最良の方法は、手動でそれを行うことです。

new_list = [] 
for item in old_list: 
    if item[0] == 'start': 
     new_list.append([item]) 
    else: 
     new_list[-1].append(item) 

注最初のタプルがスターターでない場合はエラーになること。終了点も無視されるので、開始点と終了点の間にないタプルは、最後の最後と同じリストに追加されます。あなたがそこにあるかもしれないすべての問題をキャッチしたい場合は、それはもう少し複雑だ:

new_list = [] 
in_list = False 
for item in old_list: 
    if item[0] == 'start': 
     if in_list: 
      raise ValueError("The last list hasn't completed yet.") 
     new_list.append([item]) 
     in_list = True 
    else: 
     if item[0] == 'end': 
      if not in_list: 
       raise ValueError("The list has already completed.") 
      in_list = False 

     # If this is a problem, it will throw its own error 
     new_list[-1].append(item) 
1

ソリューションenumeratezipiter機能使用:

list1 = [('start',1),('item_1',4),('item_2',2),('end',1),('start',10),('item_1',5),('item_3',2),('end',1),('start',10),('item_1',5),('item_3',2),('item_3',9),('end',1)] 

grouped_list = [list1[r[0]:r[1]+1] 
       for r in list(zip(*[iter([k for k,t in enumerate(list1) 
              if t[0] in ('start','end')])] * 2))] 

print(grouped_list) 

出力を:

[[('start', 1), ('item_1', 4), ('item_2', 2), ('end', 1)], [('start', 10), ('item_1', 5), ('item_3', 2), ('end', 1)], [('start', 10), ('item_1', 5), ('item_3', 2), ('item_3', 9), ('end', 1)]] 

詳細

  • zip(*[iter(sequence)] * n))は(iter(sequence)が提示)イテレータから項目を引くし、それぞれの項目のスライスを取得する(連続)end

  • list1[r[0]:r[1]+1]からstartからインデックスポイント2つのアイテムのタプルを行いますstart - end境界範囲

関連する問題