3

我有一个小代码,它需要一个对象列表,并且只输出列表中唯一的项目。

这是我的代码

def only_once(a):
    return [x for x in a if a.count(x) is 1]

不过,我的老师要求我们为此功能使用集合。有人可以告诉我我能做什么吗?

我的代码必须接受 a=[1,4,6,7,3,2,4,5,7,5,6] 之类的输入,然后输出 [1, 3, 2]。也必须保持它的顺序。

4

3 回答 3

3

澄清一下,您想要的是一组出现一次且仅出现一次的项目。

这里最好的选择是使用collections.Counter(),因为这意味着您只计算项目一次,而不是每个项目一次,从而大大提高性能:

>>> import collections
>>> {key for key, count in collections.Counter(a).items() if count == 1}
{1, 2, 3}

我们只需用花括号替换方括号,以表示集合推导优于列表推导,从而获得一组结果。

于 2012-10-14T20:59:48.823 回答
3

如果您需要多次删除列表中的任何项目,而不仅仅是第一个之后的出现,您可以使用:

# without using generators / comprehensions
def only_once(iterable):
    seen = set()
    duplicates = set()
    for item in iterable:
        if item in seen:
            duplicates.add(item)
        seen.add(item)
    result = []
    for item in iterable:
        if item not in duplicates:
            result.append(item)
    return result

对于一般的订单保留重复消除,请参阅unique_everseenitertools recipes

def unique_everseen(iterable, key=None):
    "List unique elements, preserving order. Remember all elements ever seen."
    # unique_everseen('AAAABBBCCDAABBB') --> A B C D
    # unique_everseen('ABBCcAD', str.lower) --> A B C D
    seen = set()
    seen_add = seen.add
    if key is None:
        for element in ifilterfalse(seen.__contains__, iterable):
            seen_add(element)
            yield element
    else:
        for element in iterable:
            k = key(element)
            if k not in seen:
                seen_add(k)
                yield element
于 2012-10-14T21:09:09.010 回答
3

[我假设您也是 user1744238 和 user1744316 - 请选择一个用户名并坚持使用它,这样更容易检查您提出的问题的变体以及您已经尝试过的问题。]

一种基于集合的方法是使用两个集合作为计数器。你只关心你是否见过一次或不止一次。例如,这是一个易于解释的方法:

  1. once为和做一个空集more
  2. 循环遍历列表的每个元素,并且:
    1. 如果您以前没有看过它,请将其添加到once.
    2. 如果您看过一次,请将其删除once并添加到more.
  3. 现在您知道在 set 中您只看到过一次的元素once
  4. 循环遍历列表的元素,如果您已经看过一次,请将其添加到输出列表中,然后将其从once集合中删除,这样您就不会两次输出相同的元素。

这给了我:

In [49]: f([1,4,6,7,3,2,4,5,7,5,6])
Out[49]: [1, 3, 2]
于 2012-10-14T21:11:37.150 回答