折叠 Python 列表,保留唯一列和最高值

Posted

技术标签:

【中文标题】折叠 Python 列表,保留唯一列和最高值【英文标题】:Collapse Python list, keeping unique columns and highest value 【发布时间】:2018-07-31 21:18:41 【问题描述】:

我有一个列表列表

data = [ ['fruit', 'apple', 'v1', 'data 1'],
         ['fruit', 'apple', 'v2', 'data 2'],
         ['fruit', 'apple', 'v3', 'data 3'],
         ['fruit', 'banana', 'v1', 'data 4'],
         ['fruit', 'banana', 'v2', 'data 5'],
         ['animal', 'dog', 'v1', 'data 6'] ]

如何根据前 2 列折叠并使用最高 v 的数据?

result = [ ['fruit', 'apple', 'v3', 'data 3'],
           ['fruit', 'banana', 'v2', 'data 5'],
           ['animal', 'dog', 'v1', 'data 6'] ]

列表在第一列中排序,但第二列没有。我的解决方案是假设两列都已排序,因此它不起作用,我不知道从哪里开始。

previous = []
result = []
for a, b, c, d in data:
    if not all(x in previous for x in [a, b]):
        final.append([a, b, c, d])
        previous = [a, b, c, d]
    else:
        if previous[2] < c:
            final[-1][2] = c
            final[-1][3] = d
            previous = [a, b, c, d]
print result

【问题讨论】:

列表排序了吗?另外,你试过什么?请展示您解决问题的尝试。 列表按第 0 列排序,但第 1 列未排序。起初我认为两者都会被排序,所以我想出了这个解决方案。编辑它。 现在第二列没有排序,我真的不知道从哪里开始。 【参考方案1】:

另一种可能的方法:

(1) 创建一个映射第一列和第二列索引的字典,并映射每对的最新索引。这样可以让数据在最后正确排序。

(2) 为第一列和第二列的所有不同分组创建一个collections.defaultdict

(3) 从 (2) 中找到每个分组的最大 v 值,并将其与其余元素组合。这将作为折叠列表返回。

(4) 根据 (1) 对折叠的列表进行排序。

示例代码:

from collections import defaultdict

data = [['fruit', 'apple', 'v1', 'data 1'],
        ['fruit', 'apple', 'v2', 'data 2'],
        ['fruit', 'apple', 'v3', 'data 3'],
        ['fruit', 'banana', 'v1', 'data 4'],
        ['fruit', 'banana', 'v2', 'data 5'],
        ['animal', 'dog', 'v1', 'data 6']]

groups = defaultdict(list)
sort_map = 
for i, (fst, snd, *rest) in enumerate(data):
    sort_map[(fst, snd)] = i
    groups[(fst, snd)].append(rest)

result = sorted((list(k) + max(v) for k, v in groups.items()), 
                                      key=lambda x: sort_map[(x[0], x[1])])

print(result)

输出:

[['fruit', 'apple', 'v3', 'data 3'], 
 ['fruit', 'banana', 'v2', 'data 5'], 
 ['animal', 'dog', 'v1', 'data 6']]

【讨论】:

【参考方案2】:

你可以使用:

[Python]: itertools.groupby(iterable, key=None) - 根据 1st 2 个值对(外部)列表元素进行分组(例如 ("fruit", "banana")) [Python]: max(iterable, *[, key, default]) - 根据他们的第 3rd 元素(第 1st 字母(“v”)+ 后面的数字来获得一个这样的组的最大值它(已修复,可处理多于一位的数字)) [Python]: Lambda Expressions - 指定分组标准
>>> import itertools
>>>
>>> data = [['fruit', 'apple', 'v1', 'some data'],
...          ['fruit', 'apple', 'v2', 'some data'],
...          ['fruit', 'apple', 'v3', 'some data'],
...          ['fruit', 'banana', 'v1', 'some data'],
...          ['fruit', 'banana', 'v2', 'some data'],
...          ['animal', 'dog', 'v1', 'some data']]
>>>
>>> [max(item[1], key=lambda x: (x[2][0], int(x[2][1:]))) for item in itertools.groupby(data, key=lambda x: (x[0], x[1]))]
[['fruit', 'apple', 'v3', 'some data'], ['fruit', 'banana', 'v2', 'some data'], ['animal', 'dog', 'v1', 'some data']]

或者您可以采用(老式)手动方式(例如使用辅助字典):

>>> helper_dict = dict()
>>> for item in data:
...    item_v = helper_dict.get((item[0], item[1]), (None, None, "v0"))[2]
...    if (item_v[0], int(item_v[1:])) < (item[2][0], int(item[2][1:])):
...             helper_dict[(item[0], item[1])] = item
...
>>> print(list(helper_dict.values()))
[['fruit', 'apple', 'v3', 'some data'], ['animal', 'dog', 'v1', 'some data'], ['fruit', 'banana', 'v2', 'some data']]

【讨论】:

【参考方案3】:

这是一种方式。

import pandas as pd

data = [ ['fruit', 'apple', 'v1', 'data 1'],
         ['fruit', 'apple', 'v2', 'data 2'],
         ['fruit', 'apple', 'v3', 'data 3'],
         ['fruit', 'banana', 'v1', 'data 4'],
         ['fruit', 'banana', 'v2', 'data 5'],
         ['animal', 'dog', 'v1', 'data 6'] ]

df = pd.DataFrame(data, columns=['Col1', 'Col2', 'Col3', 'Col4'])
df['Grouper'] = df['Col1'] + df['Col2']
df['Order'] = df['Col3'].map(lambda x: int(x[-1]))

df = df.sort_values(['Grouper', 'Order'], ascending=[True, False])\
       .drop_duplicates('Grouper')\
       .drop(['Grouper', 'Order'], 1)

lst = df.values.tolist()

# [['animal', 'dog', 'v1', 'data 6'],
#  ['fruit', 'apple', 'v3', 'data 3'],
#  ['fruit', 'banana', 'v2', 'data 5']]

【讨论】:

谢谢!我忘了提到 col2 中的数据也与不同的 col1 重复,并且您的代码仍然可以完美运行。请问 lambda x: int(x[-1]) 是做什么的? lambda 是一个匿名函数。这个取一个值,获取字符串的最后一个字符,然后将其转换为整数。

以上是关于折叠 Python 列表,保留唯一列和最高值的主要内容,如果未能解决你的问题,请参考以下文章

在 Python 中,从列表中删除重复项以使所有元素都是唯一的*同时保留顺序*的最快算法是啥? [复制]

试图在python中制作Circle类,现在几乎成功了,唯一剩下的问题是如何在历史列表中保留以前的半径而不是替换它[关闭]

python pandas:删除A列的重复项,保留B列中具有最高值的行

Python 在时间序列数据框中填充零并保留现有值

使用 jQuery 可排序时如何保留原始列表项

如何根据唯一列和单独列中的最高量过滤结果集?