列表理解,检查项目是否唯一

Ste*_*aly 28 python dictionary list-comprehension list

我正在尝试编写一个列表理解语句,如果它当前未包含在列表中,则只会添加一个项目.有没有办法检查当前正在构建的列表中的当前项?这是一个简短的例子:

输入

{
    "Stefan" : ["running", "engineering", "dancing"],
    "Bob" : ["dancing", "art", "theatre"],
    "Julia" : ["running", "music", "art"]
}
Run Code Online (Sandbox Code Playgroud)

产量

["running", "engineering", "dancing", "art", "theatre", "music"]
Run Code Online (Sandbox Code Playgroud)

代码不使用列表理解

output = []
for name, hobbies in input.items():
    for hobby in hobbies:
        if hobby not in output:
            output.append(hobby)
Run Code Online (Sandbox Code Playgroud)

我的尝试

[hobby for name, hobbies in input.items() for hobby in hobbies if hobby not in ???]
Run Code Online (Sandbox Code Playgroud)

gec*_*kon 36

您可以使用set和设置理解:

{hobby for name, hobbies in input.items() for hobby in hobbies}
Run Code Online (Sandbox Code Playgroud)

正如m.wasowski所说,我们不使用name这里,所以我们可以使用item.values():

{hobby for hobbies in input.values() for hobby in hobbies}
Run Code Online (Sandbox Code Playgroud)

如果你真的需要一个列表作为结果,你可以这样做(但请注意,通常你可以使用集合没有任何问题):

list({hobby for hobbies in input.values() for hobby in hobbies})
Run Code Online (Sandbox Code Playgroud)

  • 如果你不关心名字,你可以使用`input.values()` (3认同)
  • 我想甚至没有任何理由将其转换回列表。无论如何,该列表很可能是一组概念。 (2认同)
  • @ThijsvanDien我只是补充说,因为OP的输出在一个列表中,他可能有一些特殊的原因为什么他需要一个列表。当然,在大多数情况下你是对的。 (2认同)

Wil*_*sem 16

正如这个答案所暗示的那样:你可以使用唯一性过滤器:

def f7(seq):
    seen = set()
    seen_add = seen.add
    return [x for x in seq if not (x in seen or seen_add(x))]
Run Code Online (Sandbox Code Playgroud)

并致电:

>>> f7(hobby for name, hobbies in input.items() for hobby in hobbies)
['running', 'engineering', 'dancing', 'art', 'theatre', 'music']
Run Code Online (Sandbox Code Playgroud)

我会单独实现唯一性过滤器,因为设计规则说"不同的东西应该由不同的类/方法/组件/处理".此外,您可以根据需要重复使用此方法.

另一个优点是 - 如链接答案所写- 保留了项目的顺序.对于某些应用程序,这可能是必要的.

  • 维持秩序的要点. (2认同)
  • 公平的先生,无论如何我都赞成你的答案,因为我认为由于维持秩序,它比接受的更好.@ThijsvanDien有副作用的列表理解有什么问题?它与具有副作用的for循环几乎相同. (2认同)

m.w*_*ski 7

套和词典是你的朋友:

from collections import OrderedDict
from itertools import chain # 'flattens' collection of iterables

data = {
    "Stefan" : ["running", "engineering", "dancing"],
    "Bob" : ["dancing", "art", "theatre"],
    "Julia" : ["running", "music", "art"]
}

# using set is the easiest way, but sets are unordered:
print {hobby for hobby in chain.from_iterable(data.values())}
# output:
# set(['art', 'theatre', 'dancing', 'engineering', 'running', 'music'])


# or use OrderedDict if you care about ordering:
print OrderedDict(
        (hobby, None) for hobby in chain.from_iterable(data.values())
    ).keys()
# output:
# ['dancing', 'art', 'theatre', 'running', 'engineering', 'music']
Run Code Online (Sandbox Code Playgroud)


Bha*_*Rao 7

如果你真的想要一个listcomp而且只需要一个list-comp,你就可以做到

>>> s = []
>>> [s.append(j)  for i in d.values() for j in i if j not in s]
[None, None, None, None, None, None]
>>> s
['dancing', 'art', 'theatre', 'running', 'engineering', 'music']
Run Code Online (Sandbox Code Playgroud)

这里s是副作用的结果,d是你原来的字典.这里的独特优势在于您可以保留订单,这与其他大多数答案不同.

注意:这是一种糟糕的方式,因为它利用了list-comp,结果是副作用.不要这样做,这个答案只是告诉你,你可以单独使用list comp来实现它

  • 呃..这种解决方案不能令人沮丧. (8认同)
  • @m.wasowski 确实,你的解决方案是更好的解决方案。这只是一个替代方案。任何未来的用户肯定会在我之前看到您的答案。所以他们也会学习另一种方法。我同意这不是一个好方法,从我发布它作为答案的那一刻起我就一直这么说。至于单字母变量名。我知道它们不符合 PEP。但它在这里并没有什么坏处,因为它是列表中的第六个答案。但是,如果您仍然觉得这个答案不应该存在于此处,请提及它。我将删除它,并给未来超过 10k 的观众留言。再次感谢! (2认同)
  • @ m.wasowski:我认为SO的模型是提供*一对多*关系,从问题回答每个(dis)优势.只要有足够的警告,即使是最坏的情况,指数时间解决方案也是可以接受的.*voting*系统用于(a)过滤掉错误的答案和(b)对实际使用的答案进行排名. (2认同)
  • 哦,我...对不起表达我的意见;-)无论如何,我不会放弃你的banhammer,真的!@Bhargav Rao - 当然保留你的答案 - 并在这里回答好人.对不起,如果我的评论过于苛刻,我不是故意的. (2认同)
  • @ m.wasowski你真的不必在这抱歉!唯一的一点是,如果这个答案是第一个或第二个或FGITW那么它肯定不属于这里.答案的时机也很重要.一个错误的答案表明它为什么是坏的也有助于未来的用户不要在他们的问题解决中使用这样的策略.我希望用这张纸条清除所有看台!祝你今天愉快.:) (2认同)

Thi*_*ien 6

还有另一种写作方式,它更具描述性,你不需要嵌套(双重for)理解:

output = set.union(*[set(hobbies) for hobbies in input_.values()])
Run Code Online (Sandbox Code Playgroud)

当你将输入表示为更概念上的声音时,即使用每个人的爱好设置(因为那里也不应该重复),这就变得更好了:

input_ = {
    "Stefan" : {"running", "engineering", "dancing"},
    "Bob" : {"dancing", "art", "theatre"}, 
    "Julia" : {"running", "music", "art"}
}

output = set.union(*input_.values())
Run Code Online (Sandbox Code Playgroud)


Sha*_*ank 5

列表理解不适合这个问题.我认为一套理解会更好,但是由于这已经在另一个答案中显示,我将展示一种用紧凑的单行解决这个问题的方法:

list(set(sum(hobbies_dict.values(), [])))
Run Code Online (Sandbox Code Playgroud)

另一个使用按位或运算符的有趣解决方案,它用作集合的联合运算符:

from operator import or_
from functools import reduce # Allowed, but unnecessary in Python 2.x
list(reduce(or_, map(set, hobbies_dict.values())))
Run Code Online (Sandbox Code Playgroud)

或者(无意的双关语,我发誓),而不是使用按位或运算符,只需使用set.union并传递值的解压缩集映射.无需导入or_reduce!这个想法的灵感来自Thijs van Dien的回答.

list(set.union(*map(set, hobbies_dict.values())))
Run Code Online (Sandbox Code Playgroud)