2

Python初心者なので、この非常に単純なことを解決する必要があります。クラスがあるとします:

class Event():
  eid = 0
  events = []

  def __repr__(self):
    return "id:"+str(self.eid) + "=>" + str(self.events)

  def __str__(self):
    return self.__repr__()

いくつかのインスタンスを作成してリストに保存しましょう

eventset = list()
e1 = Event()
e1.eid = 0
e1.events = [('1','2','3','A')]

e3 = Event()
e3.eid = 1
e3.events = [('4','5','6','A')]

e2 = Event()
e2.eid = 0
e2.events = [('7','8','9','A')]

e4 = Event()
e4.eid = 1
e4.events = [('10','11','12','A')]

eventset.append(e1,e2,e3,e4)

print イベントセットは次のようになります。

[id:0=>[('1', '2', '3', 'A')], id:0=>[('7', '8', '9', 'A')], id:1=>[('4', '5', '6',   'A')], id:1=>[('10', '11', '12', 'A')]]

次のような新しいリストを作成したい:

[id:0=>[('1', '2', '3', 'A'),('7', '8', '9', 'A')], id:1=>[('4', '5', '6','A'),('10', '11', '12', 'A')]]

これをエレガントな「Pythonicな方法」で行うにはどうすればよいですか?

編集:

  1. リスト上の Event 要素の順序を保持する必要がある

  2. 新しいイベント インスタンスのコピーを作成したくない

4

4 に答える 4

2

本当に必要なのは、キーがでeidあり、アイテムがすべてのイベントである辞書です。私はdefaultdictコレクションから辞書にデフォルトの項目(この場合はリスト)を与えるために使用しました。

from collections import defaultdict

d = defaultdict(list)

for i in [e1,e2,e3,e4]:
   d[i.eid].append(i.events[0])
于 2012-08-27T11:22:37.083 に答える
2

Eventクラスを「アップグレード」することをお勧めします。

class Event(object):  # <-- one change
    eid = 0
    events = []

    def __init__(self, eid=0, events=None): # <-- second change
        self.eid = eid
        if events is not None: self.events = list(events)

    def __repr__(self):
        return "id:"+str(self.eid) + "=>" + str(self.events)

    def __str__(self):
        return self.__repr__()

次:

from operator import add, attrgetter
from itertools import starmap, groupby

merge_event = lambda e, events: Event(e, reduce(add, map(attrgetter("events"), events), []))
list(starmap(merge_event, groupby([e1,e2,e3,e4], attrgetter("eid"))))

ここで何が起こっている

groupbyタプルのリストを持つイテレータを返します: ( key, values):

>>> list(groupby([e1,e2,e3,e4], attrgetter("eid")))
[(0, <itertools._grouper object at 0x105d96bd0>), (1, <itertools._grouper object at 0x105d96f10>)]

wherekeyはグループ化基準でありvalues、一致したアイテムの反復子です。このコードでは、 key=eid属性 ( attrgetter("eid")) およびvalues= すべての項目が同じeid値です。

starmapジェネリックと同じように動作しmapますが、a) リストの代わりにイテレータを返します。b) 指定されたコールバック関数を別々の引数 ( f(*(key,value)) = f(key, values)) で呼び出します。出力merge_eventで動作する特別な関数を作成しました。groupby

merge_event( key, values) タプルを引数として取り、1 つのEventオブジェクトを生成します。(これkeyは実際にはeid) で、すべてが明確です。イベントのリストを作成するには、reduce関数とadd演算子 (operatorモジュールからの関数表現) を使用します。次のように動作します。

>>> reduce(add, [[1,2,3], ["A","B","C"]], [])
[1, 2, 3, 'A', 'B', 'C']

最後に、属性の値のみのオブジェクトのリスト (イベントのリスト) をmap(attrgetter("events"), events)収集します。Eventevents

于 2012-08-27T11:36:58.893 に答える
0

それで、私はかなり素晴らしく、非常にエレガントな解決策を見つけたと思います。見て、commet/simplify してください。

この eid がまだ返されていない場合にのみ、eid を持つ要素を返すイテレータを作成しました。

class first_unique_iter(object):
  def __init__(self, mylist):
    self.eventset = mylist
    self.i = iter(mylist)
    self.used = []

  def __iter__(self):
    return self

  def next(self):
    element = self.i.next()
    if element.eid not in self.used:
        self.used.append(element.eid)
        return element
    else:
        return self.next()

次に、ロジックが続きます。

def slice_by_id(event, eventset):
   return [e for e in eventset if e.eid == event.eid]

def reduce_2one(x,y):
   x.events.extend(y.events)
   return x

final = [reduce(reduce_2one, slice_by_id(event,eventset)) for event in  first_unique_iter(eventset)]

そのため、一意の eid が見つかった最初のイベントごとに、この新しい反復子を使用して list comp を実行します。それぞれのリストを持っているので、同じ eid を持つイベントからイベントのリストを追加する必要があります。これは、eid リストによってスライスされたときに呼び出される reduce() 関数で行われます。

print final
>>> [id:0=>[('1', '2', '3', 'A'), ('7', '8', '9', 'A')], id:1=>[('4', '5', '6', 'A'), ('10', '11', '12', 'A')]]

それをさらに単純化できますか?

于 2012-08-27T20:34:41.813 に答える
0

@ Burkan Khalid のソリューションが最も簡単です。

d工夫するために、出力辞書を別のイベント リストに変換できます。

grouped_events = []
for (i, v) in d:
    e = Event()
    e.eid = i
    e.events = v
    grouped_events.append(e)

もちろん、クラスがandを引数としてEvent適切__init__に取る場合、それは単純化できます...eidevents

grouped_events = [Event(i,v) for (i,v) in d.items()]
于 2012-08-27T11:30:40.587 に答える