用于各种分组的首选数据结构是

dict.这个想法是使用唯一标识组的东西作为dict的密钥,并将属于同一组的所有值存储在同一个密钥下.

例如,您的数据可以存储在这样的dict中:

{1: ['a', 'b'],

2: ['x']}

您用于对值进行分组的整数用作dict键,值将在列表中聚合.

我们使用dict的原因是因为它可以在恒定的O(1)时间内将键映射到值.这使得分组过程非常有效并且也非常容易.对于所有类型的分组任务,代码的一般结构将始终相同:您迭代数据并逐渐填充具有分组值的dict.使用defaultdict而不是常规字典会使整个过程变得更加容易,因为我们不必担心使用空列表初始化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']}

将数据分组后,剩下的就是将dict转换为所需的输出格式:

result = [(key, ''.join(values)) for key, values in groupdict.items()]

# result: [(1, 'ab'), (2, 'x')]

分组食谱

以下部分将提供不同类型的输入和输出的配方,并显示如何按各种事物分组.一切的基础是以下片段:

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

每个注释行都可以/必须根据您的使用情况进行自定义.

输入

输入数据的格式决定了如何迭代它.

在本节中,我们将自定义数据中的for值:配方行.

>值列表

通常,所有值都存储在一个平面列表中:

data = [value1, value2, value3, ...]

在这种情况下,我们只需使用for循环遍历列表:

for value in data:

>多个清单

如果您有多个列表,每个列表包含不同属性的值,例如

firstnames = [firstname1, firstname2, ...]

middlenames = [middlename1, middlename2, ...]

lastnames = [lastname1, lastname2, ...]

使用zip函数同时迭代所有列表:

for value in zip(firstnames, middlenames, lastnames):

这将使值成为(名字,中间名,姓氏)的元组.

>多个dicts或dicts列表

如果你想结合多个dicts

dict1 = {'a': 1, 'b': 2}

dict2 = {'b': 5}

首先将它们全部放在一个列表中:

dicts = [dict1, dict2]

然后使用两个嵌套循环迭代所有(键,值)对:

for dict_ in dicts:

for value in dict_.items():

在这种情况下,value变量将采用2元素元组的形式,如(‘a’,1)或(‘b’,2).

分组

在这里,我们将介绍从数据中提取组标识符的各种方法.

在本节中,我们将自定义组= ???食谱线.

>按list / tuple / dict元素分组

如果您的值是列表或元组(如attr1,attr2,attr3,…),并且您希望按第n个元素对它们进行分组:

group = value[n]

dicts的语法是相同的,所以如果你有{‘firstname’:’foo’,’lastname’:’bar’}这样的值,你想按名字分组:

group = value['firstname']

>按属性分组

如果您的值是像datetime.date(2018,5,27)这样的对象,并且您希望按属性对它们进行分组,例如年份:

group = value.year

>按键功能分组

有时你有一个函数在调用时返回一个值的组.例如,您可以使用len函数按其长度对值进行分组:

group = len(value)

>按多个值分组

如果您希望按多个值对数据进行分组,则可以使用tuple作为组标识符.例如,要按字符串的首字母和长度对字符串进行分组:

group = (value[0], len(value))

>按不可用的东西分组

因为dict键必须是hashable,所以如果尝试按无法散列的内容进行分组,则会遇到问题.在这种情况下,您必须找到将不可消息值转换为可哈希表示的方法.

> sets:将设置转换为frozensets,可以清除:

group = frozenset(group)

> dicts:Dicts可以表示为排序(键,值)元组:

group = tuple(sorted(group.items()))

修改聚合值

有时您会想要修改您正在分组的值.例如,如果您按第一个元素对(1,’a’)和(1,’b’)这样的元组进行分组,则可能需要从每个元组中删除第一个元素以获得类似{1:[ ‘a’,’b’]}而不是{1:[(1,’a’),(1,’b’)]}.

在本节中,我们将自定义值= ???食谱线.

>没有变化

如果您不想以任何方式更改值,只需删除值= ???你的代码中的一行.

>只保留一个列表/元组/字典元素

如果您的值是[1,’a’]之类的列表,并且您只想保留’a’:

value = value[1]

或者,如果它们像{‘firstname’:’foo’,’lastname’:’bar’}那样,你只想保留名字:

value = value['firstname']

>删除第一个列表/元组元素

如果您的值是[1,’a’,’foo’]和[1,’b’,’bar’]之类的列表,并且您想要丢弃每个元组的第一个元素以获得类似[[‘a’的组,’foo],[‘b’,’bar’]],使用切片语法:

value = value[1:]

>删除/保留任意列表/元组/字典元素

如果您的值是[‘foo’,’bar’,’baz’]之类的列表,或者像”firstname’:’foo’,’middlename’:’bar’,’lastname’:’baz’}这样的列表,你想要的删除或保留其中一些元素,首先要创建要保留或删除的元素的set.例如:

indices_to_keep = {0, 2}

keys_to_delete = {'firstname', 'middlename'}

然后从此列表中选择相应的代码段:

>保留列表元素: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]

>保留dict元素:value = {key:val表示key,val表示value.items()if key in key_to_keep]

>要删除dict元素:value = {key:val表示key,val表示value.items(),如果key不在keys_to_delete中]

产量

分组完成后,我们有一个填充列表的defaultdict.但是期望的结果并不总是(默认)dict.

在本节中,我们将自定义配方的result = groupdict行.

>一个普通的词典

要将defaultdict转换为常规字典,只需在其上调用dict构造函数:

result = dict(groupdict)

>(组,值)对的列表

要从dict {group1:[value1,value2],group2:[value3]}获得[[group1,value1],(group1,value2),(group2,value3)]的结果,请使用list comprehension:

result = [(group, value) for group, values in groupdict.items()

for value in values]

>仅包含值的嵌套列表

要从dict {group1:[value1,value2],group2:[value3]}获得[[value1,value2],[value3]]的结果,请使用dict.values:

result = list(groupdict.values())

>只是值的平面列表

要从dict {group1:[value1,value2],group2:[value3]}获得[value1,value2,value3]的结果,请使用list comprehension将dict展平:

result = [value for values in groupdict.values() for value in values]

>展平可迭代值

如果您的值是列表或其他迭代类似的

groupdict = {group1: [[list1_value1, list1_value2], [list2_value1]]}

你想要一个扁平化的结果

result = {group1: [list1_value1, list1_value2, list2_value1]}

你有两个选择:

result = {group: [x for iterable in values for x in iterable]

for group, values in groupdict.items()}

>首先使用list.extend而不是list.append来避免创建可迭代列表.换句话说,更改

groupdict[group].append(value)

groupdict[group].extend(value)

然后只需设置result = groupdict.

>排序列表

Dicts是无序数据结构.如果你遍历一个字典,你永远不知道它的元素将被列出的顺序.如果您不关心订单,可以使用上面显示的配方.但是如果您关心订单,则必须相应地对输出进行排序.

我将使用以下dict来演示如何以各种方式对输出进行排序:

groupdict = {'abc': [1], 'xy': [2, 5]}

请记住,这是一个元组合,可能需要与此答案的其他部分结合才能获得您想要的输出.一般的想法是在使用字典键从dict中提取值之前对字典键进行排序:

groups = sorted(groupdict.keys())

# groups = ['abc', 'xy']

请记住,如果要自定义排序顺序,sorted接受关键功能.例如,如果dict键是字符串,并且您希望按长度对它们进行排序:

groups = sorted(groupdict.keys(), key=len)

# groups = ['xy', 'abc']

对密钥进行排序后,使用它们以正确的顺序从dict中提取值:

# groups = ['abc', 'xy']

result = [groupdict[group] for group in groups]

# result = [[1], [2, 5]]

请记住,这可以与此答案的其他部分结合使用,以获得不同类型的输出.例如,如果要保留组标识符:

# groups = ['abc', 'xy']

result = [(group, groupdict[group]) for group in groups]

# result = [('abc', [1]), ('xy', [2, 5])]

为方便起见,以下是一些常用的排序顺序:

>按每组的值数排序:

groups = sorted(groudict.keys(), key=lambda group: len(groupdict[group]))

result = [groupdict[group] for group in groups]

# result = [[2, 5], [1]]

>计算每组中的值的数量

要计算与每个组关联的元素数,请使用len函数:

result = {group: len(values) for group, values in groupdict.items()}

如果要计算不同元素的数量,请使用set来消除重复项:

result = {group: len(set(values)) for group, values in groupdict.items()}

一个例子

为了演示如何将此配方中的工作解决方案拼凑起来,让我们尝试转换输入

data = [["A",0], ["B",1], ["C",0], ["D",2], ["E",2]]

result = [["A", "C"], ["B"], ["D", "E"]]

换句话说,我们按照第二个元素对列表进行分组.

配方的前两行总是相同的,所以让我们先复制一下:

import collections

groupdict = collections.defaultdict(list)

现在我们必须找出如何循环输入.由于我们的输入是一个简单的值列表,因此正常的for循环就足够了:

for value in data:

接下来,我们必须从值中提取组标识符.我们按第二个列表元素进行分组,因此我们使用索引:

group = value[1]

下一步是转换价值.由于我们只想保留每个列表的第一个元素,我们再次使用列表索引:

value = value[0]

最后,我们必须弄清楚如何将我们生成的字典转换为列表.我们想要的是一个没有组的值列表.我们查阅配方的输出部分以找到合适的dict flattening片段:

result = list(groupdict.values())

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"]]