如何从列表中删除类似但不重复的项目?

时间:2013-02-07 00:03:28

标签: list python-3.x

我有一个清单:

values = [[6.23234121,6.23246575],[1.352672,1.352689],[6.3245,123.35323,2.3]]

我可以通过此列表的方式将所有 0.01 内的项目移至同一列表中的其他元素。

我知道如何使用del对一组特定的列表执行此操作,但我希望它是一般,因为如果值中有n个列表,并且每个列表都有n个元素。

我想要发生的是在此列表上执行一些操作

values = [[6.23234121,6.23246575],[1.352672,1.352689],[6.3245,123.35323,2.3]]

并获得此输出

new_values = [[6.23234121],[1.352672],[6.3245,123.35323,2.3]]

1 个答案:

答案 0 :(得分:1)

我将编写一个函数来为单个列表执行此操作,例如

>>> compact([6.23234121,6.23246575], tol=.01)
[6.23234121]

然后,您可以通过[compact(l) for l in lst]将其用于嵌套结构。

这些方法中的每一个都会保留列表中没有任何东西的第一个元素;对于@ DSM的[0, 0.005, 0.01, 0.015, 0.02]示例,他们都返回[0, 0.0.15](或者,如果您将>切换为>=[0, 0.01, 0.02])。如果你想要不同的东西,你必须更准确地定义它是什么。


首先,简单的方法,类似于大卫的答案。这是O(n ^ 2):

def compact(lst, tol):
    new = []
    for el in lst:
        if all(abs(el - x) > tol for x in new):
            new.append(el)
    return compact

在三元素列表中,这非常好。但是,如果你想在三百万个元素列表中进行,那就不会削减它。让我们尝试不同的东西:

import collections
import math

def compact(lst, tol):
    round_digits = -math.log10(tol) - 1
    seen = collections.defaultdict(set)
    new = []
    for el in lst:
        rounded = round(seen, round_digits)
        if all(abs(el - x) > tol for x in seen[rounded]):
            seen[rounded].add(el)
            new.append(el)
    return new

如果您的tol0.01,那么round_digits为1.因此,6.23234121的{​​{1}}被编入索引seen只有6.2。当我们看到6.23246575后,我们将其四舍五入到6.2并在索引中查找,该索引应包含可能在我们查找的数字tol内的所有数字。然后我们仍然需要检查这些数字的距离,但只检查该索引区中的极少数,而不是整个列表。

这种方法是O(n k),其中k是将落入一个这样的bin中的平均元素数。只有当k <&lt;&lt; n(通常是这样,但这取决于您使用的数字相对于tol的分布)。请注意,它也使用的内存可能是另一种方法的两倍多,这可能是非常大的列表的问题。


另一种选择是先对列表进行排序;那么你只需要查看前面和后面的元素来检查冲突。