Ara*_*Fey 6 python grouping list
我有一些数据存储在列表中,我想根据值进行分组.
例如,如果我的数据是
data = [(1, 'a'), (2, 'x'), (1, 'b')]
Run Code Online (Sandbox Code Playgroud)
我希望按每个元组中的第一个值对其进行分组
result = [(1, 'ab'), (2, 'x')]
Run Code Online (Sandbox Code Playgroud)
我该怎么办呢?
更一般地说,在python中分组数据的推荐方法是什么?有没有可以帮助我的食谱?
用于各种分组的首选数据结构是dict.我们的想法是使用唯一标识组的内容作为dict的键,并将属于同一组的所有值存储在同一个键下.
例如,您的数据可以存储在这样的字典中:
{1: ['a', 'b'],
2: ['x']}
Run Code Online (Sandbox Code Playgroud)
您用于对值进行分组的整数用作dict键,值将在列表中聚合.
我们使用dict的原因是因为它可以在恒定的O(1)时间内将键映射到值.这使得分组过程非常有效并且也非常容易.对于所有类型的分组任务,代码的一般结构将始终相同:您迭代数据并逐渐填充具有分组值的dict.使用a defaultdict而不是常规dict使整个过程更加容易,因为我们不必担心用空列表初始化dict.
import collections
groupdict = collections.defaultdict(list)
for value in data:
group = value[0]
value = value[1]
groupdict[group].append(value)
# result:
# {1: ['a', 'b'],
# 2: ['x']}
Run Code Online (Sandbox Code Playgroud)
将数据分组后,剩下的就是将dict转换为所需的输出格式:
result = [(key, ''.join(values)) for key, values in groupdict.items()]
# result: [(1, 'ab'), (2, 'x')]
Run Code Online (Sandbox Code Playgroud)
以下部分将提供不同类型的输入和输出的配方,并显示如何按各种事物分组.一切的基础是以下片段:
import collections
groupdict = collections.defaultdict(list)
for value in data: # input
group = ??? # group identifier
value = ??? # value to add to the group
groupdict[group].append(value)
result = groupdict # output
Run Code Online (Sandbox Code Playgroud)
每个注释行都可以/必须根据您的使用情况进行自定义.
输入数据的格式决定了如何迭代它.
在本节中,我们将自定义for value in data:配方行.
通常,所有值都存储在一个平面列表中:
data = [value1, value2, value3, ...]
Run Code Online (Sandbox Code Playgroud)
在这种情况下,我们只需使用循环遍历列表for:
for value in data:
Run Code Online (Sandbox Code Playgroud)如果您有多个列表,每个列表包含不同属性的值,例如
firstnames = [firstname1, firstname2, ...]
middlenames = [middlename1, middlename2, ...]
lastnames = [lastname1, lastname2, ...]
Run Code Online (Sandbox Code Playgroud)
使用该zip函数同时迭代所有列表:
for value in zip(firstnames, middlenames, lastnames):
Run Code Online (Sandbox Code Playgroud)
这将成为value一个元组(firstname, middlename, lastname).
如果你想结合多个dicts
dict1 = {'a': 1, 'b': 2}
dict2 = {'b': 5}
Run Code Online (Sandbox Code Playgroud)
首先将它们全部放在一个列表中:
dicts = [dict1, dict2]
Run Code Online (Sandbox Code Playgroud)
然后使用两个嵌套循环迭代所有(key, value)对:
for dict_ in dicts:
for value in dict_.items():
Run Code Online (Sandbox Code Playgroud)
在这种情况下,value变量将采用像2 ('a', 1)或2元素元组的形式('b', 2).
在这里,我们将介绍从数据中提取组标识符的各种方法.
在本节中,我们将自定义group = ???配方行.
如果您的值是列表或元组,(attr1, attr2, attr3, ...)并且您希望按第n个元素对它们进行分组:
group = value[n]
Run Code Online (Sandbox Code Playgroud)
dicts的语法相同,因此如果您有类似的值,{'firstname': 'foo', 'lastname': 'bar'}并且您希望按名字分组:
group = value['firstname']
Run Code Online (Sandbox Code Playgroud)如果您的值是类似的对象,datetime.date(2018, 5, 27)并且您希望按属性对它们进行分组,例如year:
group = value.year
Run Code Online (Sandbox Code Playgroud)有时你有一个函数在调用时返回一个值的组.例如,您可以使用该len函数按其长度对值进行分组:
group = len(value)
Run Code Online (Sandbox Code Playgroud)如果您希望按多个值对数据进行分组,则可以使用元组作为组标识符.例如,要按字符串的首字母和长度对字符串进行分组:
group = (value[0], len(value))
Run Code Online (Sandbox Code Playgroud)因为dict键必须是可清除的,所以如果你尝试按无法散列的内容进行分组,则会遇到问题.在这种情况下,您必须找到将不可消息值转换为可散列表示的方法.
sets:将集合转换为 frozensets,可以清除:
group = frozenset(group)
Run Code Online (Sandbox Code Playgroud)类型的字典:日文N3 N4 N5可被表示为分类(key, value)的元组:
group = tuple(sorted(group.items()))
Run Code Online (Sandbox Code Playgroud)有时您会想要修改您正在分组的值.例如,如果您将元组分组为第一个元素(1, 'a')和(1, 'b')第一个元素,则可能需要从每个元组中删除第一个元素以获得结果,{1: ['a', 'b']}而不是{1: [(1, 'a'), (1, 'b')]}.
在本节中,我们将自定义value = ???配方行.
如果您不想以任何方式更改值,只需value = ???从代码中删除该行.
如果您的值是列表[1, 'a'],您只想保留'a':
value = value[1]
Run Code Online (Sandbox Code Playgroud)
或者,如果他们是喜欢的{'firstname': 'foo', 'lastname': 'bar'},你只想保留名字:
value = value['firstname']
Run Code Online (Sandbox Code Playgroud)如果您的值是像[1, 'a', 'foo']和的列表,[1, 'b', 'bar']并且您想要丢弃每个元组的第一个元素以获得类似的组[['a', 'foo], ['b', 'bar']],请使用切片语法:
value = value[1:]
Run Code Online (Sandbox Code Playgroud)如果您的值是像['foo', 'bar', 'baz']或类似的列表,{'firstname': 'foo', 'middlename': 'bar', 'lastname': 'baz'}并且您想要删除或仅保留其中一些元素,请首先创建一组要保留或删除的元素.例如:
indices_to_keep = {0, 2}
keys_to_delete = {'firstname', 'middlename'}
Run Code Online (Sandbox Code Playgroud)
然后从此列表中选择相应的代码段:
value = [val for i, val in enumerate(value) if i in indices_to_keep]value = [val for i, val in enumerate(value) if i not in indices_to_delete]value = {key: val for key, val in value.items() if key in keys_to_keep]value = {key: val for key, val in value.items() if key not in keys_to_delete]分组完成后,我们就会填写一份defaultdict清单.但是期望的结果并不总是(默认)dict.
在本节中,我们将自定义result = groupdict配方行.
要将defaultdict转换为常规字典,只需dict在其上调用构造函数:
result = dict(groupdict)
Run Code Online (Sandbox Code Playgroud)(group, value)对要从[(group1, value1), (group1, value2), (group2, value3)]dict 获得结果{group1: [value1, value2], group2: [value3]},请使用列表推导:
result = [(group, value) for group, values in groupdict.items()
for value in values]
Run Code Online (Sandbox Code Playgroud)要从[[value1, value2], [value3]]dict 获得结果{group1: [value1, value2], group2: [value3]},请使用dict.values:
result = list(groupdict.values())
Run Code Online (Sandbox Code Playgroud)要获得类似于[value1, value2, value3]dict 的结果{group1: [value1, value2], group2: [value3]},请使用列表理解来展平dict :
result = [value for values in groupdict.values() for value in values]
Run Code Online (Sandbox Code Playgroud)如果您的值是列表或其他迭代类似的
groupdict = {group1: [[list1_value1, list1_value2], [list2_value1]]}
Run Code Online (Sandbox Code Playgroud)
你想要一个扁平化的结果
result = {group1: [list1_value1, list1_value2, list2_value1]}
Run Code Online (Sandbox Code Playgroud)
你有两个选择:
用dict理解来展平列表:
result = {group: [x for iterable in values for x in iterable]
for group, values in groupdict.items()}
Run Code Online (Sandbox Code Playgroud)首先避免使用list.extend而不是创建可迭代列表list.append.换句话说,改变
groupdict[group].append(value)
Run Code Online (Sandbox Code Playgroud)
至
groupdict[group].extend(value)
Run Code Online (Sandbox Code Playgroud)
然后就开始吧result = groupdict.
Dicts是无序数据结构.如果迭代dict,你永远不知道它的元素将以哪种顺序列出.如果您不关心订单,可以使用上面显示的配方.但是,如果你做有关订单的照顾,你要输出相应的排序.
我将使用以下dict来演示如何以各种方式对输出进行排序:
groupdict = {'abc': [1], 'xy': [2, 5]}
Run Code Online (Sandbox Code Playgroud)
请记住,这是一个元组合,可能需要与此答案的其他部分结合才能获得您想要的输出.一般的想法是在使用字典键从dict中提取值之前对字典键进行排序:
groups = sorted(groupdict.keys())
# groups = ['abc', 'xy']
Run Code Online (Sandbox Code Playgroud)
请记住,sorted如果要自定义排序顺序,则接受关键功能.例如,如果dict键是字符串,并且您希望按长度对它们进行排序:
groups = sorted(groupdict.keys(), key=len)
# groups = ['xy', 'abc']
Run Code Online (Sandbox Code Playgroud)
对密钥进行排序后,使用它们以正确的顺序从dict中提取值:
# groups = ['abc', 'xy']
result = [groupdict[group] for group in groups]
# result = [[1], [2, 5]]
Run Code Online (Sandbox Code Playgroud)
请记住,这可以与此答案的其他部分结合使用,以获得不同类型的输出.例如,如果要保留组标识符:
# groups = ['abc', 'xy']
result = [(group, groupdict[group]) for group in groups]
# result = [('abc', [1]), ('xy', [2, 5])]
Run Code Online (Sandbox Code Playgroud)
为方便起见,以下是一些常用的排序顺序:
按每组值的数量排序:
groups = sorted(groudict.keys(), key=lambda group: len(groupdict[group]))
result = [groupdict[group] for group in groups]
# result = [[2, 5], [1]]
Run Code Online (Sandbox Code Playgroud)要计算与每个组关联的元素数,请使用以下len函数:
result = {group: len(values) for group, values in groupdict.items()}
Run Code Online (Sandbox Code Playgroud)
如果要计算不同元素的数量,请使用set以消除重复:
result = {group: len(set(values)) for group, values in groupdict.items()}
Run Code Online (Sandbox Code Playgroud)为了演示如何将此配方中的工作解决方案拼凑在一起,让我们尝试转换输入
data = [["A",0], ["B",1], ["C",0], ["D",2], ["E",2]]
Run Code Online (Sandbox Code Playgroud)
成
result = [["A", "C"], ["B"], ["D", "E"]]
Run Code Online (Sandbox Code Playgroud)
换句话说,我们按照第二个元素对列表进行分组.
配方的前两行总是相同的,所以让我们先复制一下:
import collections
groupdict = collections.defaultdict(list)
Run Code Online (Sandbox Code Playgroud)
现在我们必须找出如何循环输入.由于我们的输入是一个简单的值列表,因此正常for循环就足够了:
for value in data:
Run Code Online (Sandbox Code Playgroud)
接下来,我们必须从值中提取组标识符.我们按第二个列表元素进行分组,因此我们使用索引:
group = value[1]
Run Code Online (Sandbox Code Playgroud)
下一步是转换价值.由于我们只想保留每个列表的第一个元素,我们再次使用列表索引:
value = value[0]
Run Code Online (Sandbox Code Playgroud)
最后,我们必须弄清楚如何将我们生成的字典转换为列表.我们想要的是一个没有组的值列表.我们查阅配方的输出部分以找到合适的dict展平片段:
result = list(groupdict.values())
Run Code Online (Sandbox Code Playgroud)
Etvoilà:
data = [["A",0], ["B",1], ["C",0], ["D",2], ["E",2]]
import collections
groupdict = collections.defaultdict(list)
for value in data:
group = value[1]
value = value[0]
groupdict[group].append(value)
result = list(groupdict.values())
# result: [["A", "C"], ["B"], ["D", "E"]]
Run Code Online (Sandbox Code Playgroud)