Python: 将具有相同第一个元素的元组分组

8

i have a tuple like this

[
(379146591, 'it', 55, 1, 1, 'NON ENTRARE', 'NonEntrate', 55, 1), 
(4746004, 'it', 28, 2, 2, 'NON ENTRARE', 'NonEntrate', 26, 2), 
(4746004, 'it', 28, 2, 2, 'TheBestTroll Group', 'TheBestTrollGroup', 2, 3)
]

我希望得到这个而不是那个:
[
(379146591, (('it', 55, 1, 1, 'NON ENTRARE', 'NonEntrate', 55, 1)), 
(4746004, (('it', 28, 2, 2, 'NON ENTRARE', 'NonEntrate', 26, 2), ('it', 28, 2, 2, 'TheBestTroll Group', 'TheBestTrollGroup', 2, 3)))
]

对于任何元素来说,除了第一个元素外的所有内容都在它的子元组中,如果下一个元素有与第一个元素相同的元素,则将其设置为前一个元组的另一个子元组。

所以我可以这样做:

for i in data:
    # getting the first element of the list
    for sub_i in i[1]:
        # i access all the tuples inside

有没有一些函数可以做到这一点?

1
我认为这是使用字典的好方法。您可以将第一个元素用作键,而值可以是元组列表。 - Kyle
@Kyle 好的,谢谢。我在想是否有一个库有这样的函数,还是我需要自己编写。 - 91DarioDev
你不需要使用库来完成这个。我可以用字典在这里写一个示例。查看@Psidom的答案。 - Kyle
4个回答

12

使用 defaultdict 相当简单;你可以将默认值初始化为一个列表,然后将项目附加到相同键的值中:

lst = [
    (379146591, 'it', 55, 1, 1, 'NON ENTRARE', 'NonEntrate', 55, 1), 
    (4746004, 'it', 28, 2, 2, 'NON ENTRARE', 'NonEntrate', 26, 2), 
    (4746004, 'it', 28, 2, 2, 'TheBestTroll Group', 'TheBestTrollGroup', 2, 3)
]

from collections import defaultdict    ​
d = defaultdict(list)

for k, *v in lst:
    d[k].append(v)

list(d.items())
#[(4746004,
#  [('it', 28, 2, 2, 'NON ENTRARE', 'NonEntrate', 26, 2),
#   ('it', 28, 2, 2, 'TheBestTroll Group', 'TheBestTrollGroup', 2, 3)]),
# (379146591, [('it', 55, 1, 1, 'NON ENTRARE', 'NonEntrate', 55, 1)])]
如果顺序很重要,可以使用 OrderedDict,它可以记住插入的顺序。

from collections import OrderedDict
d = OrderedDict()
​
for k, *v in lst:
    d.setdefault(k, []).append(v)

list(d.items())
#[(379146591, [['it', 55, 1, 1, 'NON ENTRARE', 'NonEntrate', 55, 1]]),
# (4746004,
#  [['it', 28, 2, 2, 'NON ENTRARE', 'NonEntrate', 26, 2],
#   ['it', 28, 2, 2, 'TheBestTroll Group', 'TheBestTrollGroup', 2, 3]])]

1
自从CPython 3.6及其他所有Python实现开始支持Python 3.7,您就不需要使用OrderedDict了,因为普通的dict维护插入顺序。参考链接 - user3064538

4
使用 itertools.groupby(和operator.itemgetter获取第一项)。唯一需要注意的是,数据需要先排序,这样分组才会一个接一个地出现(如果您使用了 uniqsort bash 命令,则相同的道理),您可以使用 sorted() 来实现排序。
import operator
from itertools import groupby

data = [
    (379146591, "it", 55, 1, 1, "NON ENTRARE", "NonEntrate", 55, 1),
    (4746004, "it", 28, 2, 2, "NON ENTRARE", "NonEntrate", 26, 2),
    (4746004, "it", 28, 2, 2, "TheBestTroll Group", "TheBestTrollGroup", 2, 3),
]

data = sorted(data, key=operator.itemgetter(0))  # this might be unnecessary
for k, g in groupby(data, operator.itemgetter(0)):
    print(k, list(g))

将输出

4746004 [(4746004, 'it', 28, 2, 2, 'NON ENTRARE', 'NonEntrate', 26, 2), (4746004, 'it', 28, 2, 2, 'TheBestTroll Group', 'TheBestTrollGroup', 2, 3)]
379146591 [(379146591, 'it', 55, 1, 1, 'NON ENTRARE', 'NonEntrate', 55, 1)]

在您的情况下,您还需要从值列表中删除第一个元素。将上面代码的最后两行更改为以下内容:
for k, g in groupby(data, operator.itemgetter(0)):
    print(k, [item[1:] for item in g])

输出:

4746004 [('it', 28, 2, 2, 'NON ENTRARE', 'NonEntrate', 26, 2), ('it', 28, 2, 2, 'TheBestTroll Group', 'TheBestTrollGroup', 2, 3)]
379146591 [('it', 55, 1, 1, 'NON ENTRARE', 'NonEntrate', 55, 1)]

3
您可以使用Python3变量解包和OrderedDict来保留顺序:
from collections import OrderedDict
d = OrderedDict()
l = [
  (379146591, 'it', 55, 1, 1, 'NON ENTRARE', 'NonEntrate', 55, 1), 
  (4746004, 'it', 28, 2, 2, 'NON ENTRARE', 'NonEntrate', 26, 2), 
 (4746004, 'it', 28, 2, 2, 'TheBestTroll Group', 'TheBestTrollGroup', 2, 3)
]

for a, *b in l:
  if a in d:
     d[a].append(b)
  else:
     d[a] = [b]

final_data = [(a, tuple(map(tuple, b))) for a, b in d.items()]

输出:

[(379146591, (('it', 55, 1, 1, 'NON ENTRARE', 'NonEntrate', 55, 1),)), (4746004, (('it', 28, 2, 2, 'NON ENTRARE', 'NonEntrate', 26, 2), ('it', 28, 2, 2, 'TheBestTroll Group', 'TheBestTrollGroup', 2, 3)))]

从 CPython 3.6 开始,以及所有其他 Python 实现从 Python 3.7 开始,你不需要 OrderedDict,因为普通的 dict 会维护插入顺序。 - user3064538

0

你可以使用 collection.defaultdict:

data = [
    (379146591, 'it', 55, 1, 1, 'NON ENTRARE', 'NonEntrate', 55, 1), 
    (4746004, 'it', 28, 2, 2, 'NON ENTRARE', 'NonEntrate', 26, 2), 
    (4746004, 'it', 28, 2, 2, 'TheBestTroll Group', 'TheBestTrollGroup', 2, 3)
    ]
from collections import defaultdict
a = defaultdict(list)
a = defaultdict(list)


from collections import defaultdict
a = defaultdict(list)

for d in data:
    a[d[0]].append(d[1:])

for k,v in a.items():
    a[k] = tuple(a[k])

print(dict(a))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接