【问题标题】:remove duplicate tuple value based on index in tuple根据元组中的索引删除重复的元组值
【发布时间】:2017-06-17 19:18:15
【问题描述】:

有没有办法根据元组中的索引删除重复的元组。说我有

[(0, 4, 1.0), (1, 4, 1.0), (3, 4, 1.0), (0, 3, 2.0), (1, 3, 2.0), (0, 2, 3.0), (1, 2, 3.0), (2, 4, 4.0), (2, 3, 5.0), (0, 1, inf)]

我可以随机保留一个元组,其中每个重复项在索引 2 处具有相同的值吗?

因此,有 3 个元组在索引 2 处具有值 1.0,两个元组在索引 2 处具有值 2.0,一个在索引 2 处具有值 3,依此类推。

因此,(0, 4, 1.0) 可能从索引 2 处的值 1.0 中随机选择,而 (1, 3, 2.0) 可能从索引 2 处的值 2.0 中随机选择。 比如说,(1, 2, 3.0) 是从索引 2 处的值 3.0 中随机选择的。 然后,我的列表看起来像

[(0, 4, 1.0),(1, 3, 2.0), (1, 2, 3.0), (2, 4, 4.0), (2, 3, 5.0), (0, 1, inf)]

我从来没有遇到过这样的功能,或者至少是有效的。

【问题讨论】:

  • 输入中索引 2 处具有相同值的所有元组是否彼此相邻?如果不是,输出的正确顺序是什么?
  • 我可以将它们排序为像上面一样

标签: python list random duplicates tuples


【解决方案1】:

您可以使用 itertools.groupby 根据索引 2 处的值对元组进行分组。然后对于每个组,您可以使用 random.choice 选择一个元组:

>>> from itertools import groupby
>>> import random
>>> l = [(0, 4, 1.0), (1, 4, 1.0), (3, 4, 1.0), (0, 3, 2.0), (1, 3, 2.0), (0, 2, 3.0), (1, 2, 3.0), (2, 4, 4.0), (2, 3, 5.0), (0, 1, float('inf'))]
>>> [random.choice(tuple(g)) for _, g in groupby(l, key=lambda x: x[2])]
[(1, 4, 1.0), (1, 3, 2.0), (1, 2, 3.0), (2, 4, 4.0), (2, 3, 5.0), (0, 1, inf)]

在上面的groupby 返回可迭代的(key, group) 元组,其中键是给groupby 的第二个参数返回的值,组是组内元素的可迭代:

>>> [(k, tuple(g)) for k, g in groupby(l, key=lambda x: x[2])]
[(1.0, ((0, 4, 1.0), (1, 4, 1.0), (3, 4, 1.0))), (2.0, ((0, 3, 2.0), (1, 3, 2.0))), (3.0, ((0, 2, 3.0), (1, 2, 3.0))), (4.0, ((2, 4, 4.0),)), (5.0, ((2, 3, 5.0),)), (inf, ((0, 1, inf),))]

由于我们不需要密钥,我们可以丢弃它并将组转换为random.choice 期望的序列:

>>> [random.choice(tuple(g)) for _, g in groupby(l, key=lambda x: x[2])]
[(1, 4, 1.0), (1, 3, 2.0), (0, 2, 3.0), (2, 4, 4.0), (2, 3, 5.0), (0, 1, inf)]

请注意,上面期望索引 2 处具有相同值的元组在输入中彼此相邻。如果不是这种情况,您可以在将原始列表传递给groupby 之前对原始列表进行相应的排序。

更新如果您只需要结果的三个第一个值,您可以使用生成器表达式而不是列表推导式并使用islice 从那里提取值:

>>> from itertools import islice
>>> gen = (random.choice(tuple(g)) for _, g in groupby(l, key=lambda x: x[2]))
>>> list(islice(gen, 3))
[(0, 4, 1.0), (1, 3, 2.0), (0, 2, 3.0)]

【讨论】:

  • 注意:列表在与groupby一起使用之前应该根据索引2进行预排序
  • 有没有办法提取排序列表中最低的 2 个排序值,这样您就不需要遍历每个值?
  • @MikeElJackson 我不确定我是否明白你在问什么。您的意思是应该从原始输入中只考虑(0, 4, 1.0), (1, 4, 1.0)(== (3, 4, 1.0) 除外)?也许您可以稍微更新一下原始问题以提供示例。
  • 假设有一个庞大的元组列表,比如数千个,如果有重复,我希望从这个列表中随机选择 3 个最低的元组。您向我展示的代码(太棒了)让您遍历每个元素并按其分组并随机选择它。例如,您可以对 3 个最低值执行此操作,而不是按整个列表分组,因为它已经排序
  • 所以,如果我有一千个东西的列表,我只需要对最后几项使用 for 循环,而不是遍历整个列表
【解决方案2】:

我不会在一次手术中做到这一点,尽管我确信这是可能的。

我会首先为索引2 处的每个值创建一个列表:

values_at_index_2 = {t[2] for t in data}
groups_by_value = [[t for t in data if t[2] == v] for v in values_at_index_2]

然后在每个组中选择一个元组:

import random
new_data = [random.choice(group) for group in groups_by_value]

【讨论】:

    猜你喜欢
    • 2018-09-27
    • 2019-09-17
    • 2023-03-08
    • 1970-01-01
    • 2021-07-20
    • 2019-02-12
    • 1970-01-01
    • 2012-02-12
    • 2019-03-07
    相关资源
    最近更新 更多