【问题标题】:How to split a list into a list of sublists that contain duplicate values in Python?如何将列表拆分为包含 Python 中重复值的子列表列表?
【发布时间】:2018-03-28 12:17:29
【问题描述】:

我有一份关于每天特定时间潮汐信息的列表。它看起来有点像这样:

tideData = [
['Thursday 4 January',11.58,0.38],
['Thursday 4 January',16.95,0.73],
['Friday 5 January',6.48,0.83],
['Friday 5 January',12.42,0.33],
['Saturday 6 January',0.5,0.02],
['Saturday 6 January',7.18,0.85],
...
['Friday 2 February',23.52,0.04]
]

我想将此列表拆分为包含相同日期的子列表。在上述情况下,列表将变为:

tideData = [
[['Thursday 4 January',11.58,0.38],
['Thursday 4 January',16.95,0.73]],
[['Friday 5 January',6.48,0.83],
['Friday 5 January',12.42,0.33],
['Friday 5 January',17.92,0.75]],
[['Saturday 6 January',0.5,0.02],
['Saturday 6 January',7.18,0.85]],
...
['Friday 2 February',23.52,0.04]]
]

现在,如果每个日期的数量相等,这将不是问题。但是,日期有时出现两次,有时出现三次。因此,我希望能够根据重复日期将它们分类到子列表中。我该怎么办?

【问题讨论】:

标签: python python-3.x list group-by


【解决方案1】:

我想你想使用itertools 包中的groupby

from itertools import groupby

tideData = [
['Thursday 4 January',11.58,0.38],
['Thursday 4 January',16.95,0.73],
['Friday 5 January',6.48,0.83],
['Friday 5 January',12.42,0.33],
['Saturday 6 January',0.5,0.02],
['Saturday 6 January',7.18,0.85],
['Friday 2 February',23.52,0.04]
]

如果你的数据没有排序,你可以使用:

tideData = sorted(tideData, key=lambda x: x[0])

在使用以下内容之前:

[list(g) for _,g in groupby(tideData, key=lambda x: x[0])]
# returns:
[[['Thursday 4 January', 11.58, 0.38], ['Thursday 4 January', 16.95, 0.73]],
 [['Friday 5 January', 6.48, 0.83], ['Friday 5 January', 12.42, 0.33]],
 [['Saturday 6 January', 0.5, 0.02], ['Saturday 6 January', 7.18, 0.85]],
 [['Friday 2 February', 23.52, 0.04]]]

【讨论】:

  • 这是我最喜欢的方法,因为它保证稳定(只要 tideData 已经按日期排序)
  • 请注意,tideData = sorted(tideData, key=lambda x: x[0]) 中的可选参数 key=lambda x: x[0] 仅在您想保留每天的数据顺序时才需要。否则,您可以在不提供密钥的情况下进行排序。元组按字典顺序排序,x[0] 的优先级最高。
  • @DeepSpace 另请注意,python 排序是一种稳定的排序。
【解决方案2】:

您可以使用collections.defaultdict 获得 O(n) 解决方案。

在 Python 3.7 中,您将获得额外的好处,即值的顺序将与输入中的顺序相匹配。这在 Python 3.6 中有效,但被视为实现细节。

from collections import defaultdict

d = defaultdict(list)

for item in tideData:
    d[item[0]].append(item)
    
res = list(d.values())

结果:

[[['Thursday 4 January', 11.58, 0.38], ['Thursday 4 January', 16.95, 0.73]],
 [['Friday 5 January', 6.48, 0.83], ['Friday 5 January', 12.42, 0.33]],
 [['Saturday 6 January', 0.5, 0.02], ['Saturday 6 January', 7.18, 0.85]],
 [['Friday 2 February', 23.52, 0.04]]]

对于那些对 O(n) 和 O(n log n) 解决方案之间的性能差异感兴趣的人:

from collections import defaultdict
from itertools import groupby
from operator import itemgetter

tideData = [
['Thursday 4 January',11.58,0.38],
['Thursday 4 January',16.95,0.73],
['Friday 5 January',6.48,0.83],
['Friday 5 January',12.42,0.33],
['Saturday 6 January',0.5,0.02],
['Saturday 6 January',7.18,0.85],
['Friday 2 February',23.52,0.04]
]

tideData = tideData * 10000

def jp(tideData):
    d = defaultdict(list)
    for item in tideData:
        d[item[0]].append(item)
    return list(d.values())

def grp(tideData):
    grouper = groupby(sorted(tideData, key=itemgetter(0)), key=itemgetter(0))
    return [list(g) for _, g in grouper]

%timeit jp(tideData)   # 5.63 ms per loop
%timeit grp(tideData)  # 9.87 ms per loop

【讨论】:

  • “在 Python 3.6 中,您可以获得额外的好处,即值的顺序将与输入中的顺序相匹配。” Python 文档说不应该依赖它,因为它是一个实现细节,可能不会永远适用。
  • @DeepSpace,Guido 已确认 3.7 将维持秩序!所以你的报价可能会被覆盖。
  • sort+groupby 方法会产生 n log(n) 成本,这是因为排序,而不是因为 groupby。但是你实际上忘记在代码中排序了。
【解决方案3】:

这是没有任何导入的简单方法:

groub_by={}
for i,j in enumerate(tideData):
    if j[0] not in groub_by:
        groub_by[j[0]]=[j]
    else:
        groub_by[j[0]].append(j)
print(groub_by.values())

输出:

[[['Thursday 4 January', 11.58, 0.38], ['Thursday 4 January', 16.95, 0.73]], [['Saturday 6 January', 0.5, 0.02], ['Saturday 6 January', 7.18, 0.85]], [['Friday 5 January', 6.48, 0.83], ['Friday 5 January', 12.42, 0.33]], [['Friday 2 February', 23.52, 0.04]]]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-05-26
    • 1970-01-01
    • 2012-03-29
    • 2017-09-28
    • 2011-01-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多