我有一个具有suit
属性的对象数组,我想根据对象具有的子数组拆分成子数组.我目前正在使用这个:
for c in cards:
if c.suit.value == 0:
spades.append(c)
elif c.suit.value == 1:
diamonds.append(c)
elif c.suit.value == 2:
clubs.append(c)
else:
hearts.append(c)
Run Code Online (Sandbox Code Playgroud)
我尝试使用itertools.groupby
如下:
suits = [list(g) for g in intertools.groupby(cards, lambda x: x.suit.value)]
Run Code Online (Sandbox Code Playgroud)
但这只是收益:
[[3, <itertools._grouper object at 0x000000000296B2E8>], ...]
Run Code Online (Sandbox Code Playgroud)
我的第一种方法是有效的,我只想象有一个简单的pythonic one liner可以完成我的需要.
迭代时,itertools.groupby
产生tuple
对象:键和分组值的可迭代对象(允许对数据进行惰性评估)。
您只是将 the 转换tuple
为 a list
,这不是很有用。
相反,您需要删除密钥(例如通过将其解压到_
,pythonic 方式告诉您没有使用它)并强制对值进行迭代:
[list(g) for _,g in itertools.groupby(cards, lambda x: x.suit.value)]
Run Code Online (Sandbox Code Playgroud)
现在,如果您想进行分组和排序,仅仅为了创建单行(单行很好,但我更喜欢快速程序)的乐趣而传递sorted(cards)
给它并不是很有效groupby
。您的方法有效,或者您也可以使用collections.defaultdict
,甚至使用间接命名以正确的颜色命名 dict,例如:
import collections
cards = collections.defaultdict(list)
colors = ["spades","diamonds","clubs","hearts"]
for c in cards:
cards[colors[c.suit.value]].append(c)
Run Code Online (Sandbox Code Playgroud)
虽然它不是单行,但通过使用列表,我们使它更优雅:
spades, diamonds, clubs, hearts = collcard = [[] for _ in range(4)]
for c in cards:
collcard[c.suit.value].append(c)
Run Code Online (Sandbox Code Playgroud)
因此,我们在这里初始化一个包含四个空子列表的列表,然后我们将该卡附加c
到带索引的列表中c.suit.value
.
我们使用迭代拆包的第一要素分配spades
,第二个diamonds
,等等.
优点是我们避免排序(在O(n log n)中工作).因此该算法具有时间复杂度O(n)(给定列表追加的摊销成本为O(1)).
虽然oneliner通常是优雅的,但是不应该花费太多精力来写这些内容,因为oneliner可能更难理解,或者对性能有重大影响.