我有一个具有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)
我尝试使用itertools.groupby
,如下所示:
suits = [list(g) for g in intertools.groupby(cards, lambda x: x.suit.value)]
但这只是收益:
[[3, <itertools._grouper object at 0x000000000296B2E8>], ...]
我的第一种方法是有效的,我只想象有一个简单的pythonic one liner可以完成我需要的工作。
答案 0 :(得分:5)
虽然它不是单行,但通过使用列表,我们可以使它更优雅:
spades, diamonds, clubs, hearts = collcard = [[] for _ in range(4)]
for c in cards:
collcard[c.suit.value].append(c)
这里我们初始化一个包含四个空子列表的列表,然后我们将卡c
附加到索引为c.suit.value
的列表中。
我们使用iterable unpacking将第一个元素分配给spades
,将第二个元素分配给diamonds
等。
优点是我们避免排序(在 O(n log n)中工作)。因此,该算法具有时间复杂度 O(n)(假设附加列表的摊销成本为 O(1))。
虽然oneliner通常很优雅,但是编写这些内容时不应该付出太多努力,因为oneliner可能更难理解,或者对性能有重大影响。
答案 1 :(得分:4)
当迭代时,itertools.groupby
产生tuple
个对象:密钥和分组值的可迭代(允许对数据进行惰性求值)。
您刚刚将tuple
转换为list
,这不是很有用。
相反,你需要删除密钥(例如通过将其解压缩到_
,告知你没有使用它的pythonic方式)并强制迭代值:
[list(g) for _,g in itertools.groupby(cards, lambda x: x.suit.value)]
现在,如果你想对和进行分组,那么将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)
答案 2 :(得分:1)
如果您知道卡片组的大小,您可以做这样的事情,考虑是40卡牌:
allcards = sorted(cards, key=lambda x: x.suit.value)
spades, diamonds, clubs, hearts = map(lambda x: allcards[x:x+10], range(0,40,10))
基本上你得到了一个甲板的分类版本,并将其带入与套装尺寸相对应的块中。如果它们从较低的索引到较高的索引,则从黑桃到黑格尔。