2

文字列のリストがあります。例を次に示します。

wallList = ['wall_l0', 'wall_l1', 'wall_broken_l0', 'wall_broken_l1',
             'wall_vwh_l0','wall_vwh_l1', 'wall_vwh_broken_l0', 
             'wall_vwh_broken_l1', 'wall_vpi_l0', 'wall_vpi_l1', 
             'wall_vpi_broken_l0', 'wall_vpi_broken_l1']

そして、それらを壁のタイプと状態(デフォルト/壊れた)でグループ化したいと思います:

[['wall_l0', 'wall_l1'],['wall_broken_l0', 'wall_broken_l1']]

[['wall_vwh_l0', 'wall_vwh_l1'],['wall_vwh_broken_l0', 'wall_vwh_broken_l1']] 

[['wall_vpi_l0', 'wall_vpi_l1'],['wall_vpi_broken_l0', 'wall_vpi_broken_l1']]

誰もがこれを行うための最良の方法を知っていますか、またはPythonレシピを知っていますか?

4

4 に答える 4

4

これを行うための小さなワンライナーがあります:

import itertools, re
results = [list(v) for (k, v) in itertools.groupby(sorted(wallList),
        lambda x: re.sub(r'\d+', '0', x))]

これは順序を保持しませんが、それ以外の場合は、必要な出力を取得します。

これは、すべての数値が「0」に変換されたバージョンを調べ、重複をグループ化することで機能します。

于 2012-09-15T01:53:25.273 に答える
3

編集:「状態」で整理するのを忘れたので、どうやら私の答えは部分的にしか正しくありません。正解は@samy.vilarからです。

使用itertools.groupby

>>> from itertools import groupby
>>> [list(g) for k,g in groupby(sorted(wallList), lambda r: r[:-1])]
[['wall_broken_l0', 'wall_broken_l1'], ['wall_l0', 'wall_l1'], ['wall_vpi_broken_l0
', 'wall_vpi_broken_l1'], ['wall_vpi_l0', 'wall_vpi_l1'], ['wall_vwh_broken_l0', 'w
all_vwh_broken_l1'], ['wall_vwh_l0', 'wall_vwh_l1']]
于 2012-09-15T01:56:03.430 に答える
2

興味深いことに、最初に壁のタイプごとに分割して、これを実行できるようにする必要があります。

>>> from itertools import groupby
>>> wallList = ['wall_l0', 'wall_l1', 'wall_broken_l0', 'wall_broken_l1',
         'wall_vwh_l0','wall_vwh_l1', 'wall_vwh_broken_l0', 
         'wall_vwh_broken_l1', 'wall_vpi_l0', 'wall_vpi_l1', 
         'wall_vpi_broken_l0', 'wall_vpi_broken_l1']
>>> list(groupby(sorted(wallList), lambda wall: wall.replace('_broken', '')[:-3]))
[('wall', <itertools._grouper object at 0x1004edc50>), ('wall_vpi', <itertools._grouper object at 0x1004edb90>), ('wall_vwh', <itertools._grouper object at 0x1004eda90>)]

タイプが壊れているタイプで分離できるようになったので、すばらしいです。

これはすべてが一緒にどのように見えるかです。

>>> from itertools import groupby
>>> wallList = ['wall_l0', 'wall_l1', 'wall_broken_l0', 'wall_broken_l1',
         'wall_vwh_l0','wall_vwh_l1', 'wall_vwh_broken_l0', 
         'wall_vwh_broken_l1', 'wall_vpi_l0', 'wall_vpi_l1', 
         'wall_vpi_broken_l0', 'wall_vpi_broken_l1']

>>> values = [[list(v) for k, v in groupby(values, lambda value: '_broken_' in value)] 
...             for key, values in groupby(sorted(wallList), lambda wall: wall.replace('_broken', '')[:-3])]
>>> from pprint import pprint
>>> pprint(values)
[[['wall_broken_l0', 'wall_broken_l1'], ['wall_l0', 'wall_l1']],
 [['wall_vpi_broken_l0', 'wall_vpi_broken_l1'],
  ['wall_vpi_l0', 'wall_vpi_l1']],
 [['wall_vwh_broken_l0', 'wall_vwh_broken_l1'],
  ['wall_vwh_l0', 'wall_vwh_l1']]]

確かに他の方法もありますが、これは簡潔なようです。

別の方法は次のとおりです。

>>> from collections import defaultdict
>>> values = defaultdict(lambda : defaultdict(list))
>>> for wall in wallList:
...     if 'broken' in wall:
...         values[wall[:-3].replace('_broken', '')]['broken'].append(wall)
...     else:
...         values[wall[:-3]]['default'].append(wall)
... 
>>> values.items()
[('wall', defaultdict(<type 'list'>, {'default': ['wall_l0', 'wall_l1'], 'broken': ['wall_broken_l0', 'wall_broken_l1']})), ('wall_vpi', defaultdict(<type 'list'>, {'default': ['wall_vpi_l0', 'wall_vpi_l1'], 'broken': ['wall_vpi_broken_l0', 'wall_vpi_broken_l1']})), ('wall_vwh', defaultdict(<type 'list'>, {'default': ['wall_vwh_l0', 'wall_vwh_l1'], 'broken': ['wall_vwh_broken_l0', 'wall_vwh_broken_l1']}))]
>>>

この2番目の方法は、1回だけ反復し、辞書の検索は一定であり、名前と状態で任意の壁のセットにアクセスできるため、より高速になるはずです...

>>> values['wall']['default']
['wall_l0', 'wall_l1']
>>> values['wall_vpi']['default']
['wall_vpi_l0', 'wall_vpi_l1']
>>> values['wall_vpi']['broken']
['wall_vpi_broken_l0', 'wall_vpi_broken_l1']
>>>
于 2012-09-15T02:35:29.930 に答える
-2

_で分割:string.split('_')。2つのフィールドが返されると、縮退したケースになります。3を取得した場合は、3の中央のフィールドでグループ化します。リストのディクショナリが役立つか、collections.defaultdict(list)の方が適しています。

于 2012-09-15T01:49:34.300 に答える