列表理解,检查项目是否唯一
List comprehension, check if item is unique
我正在尝试编写一个列表理解语句,它只会添加当前不包含在列表中的项目。有没有办法检查当前正在构建的列表中的当前项目?这是一个简短的例子:
输入
{
"Stefan" : ["running", "engineering", "dancing"],
"Bob" : ["dancing", "art", "theatre"],
"Julia" : ["running", "music", "art"]
}
输出
["running", "engineering", "dancing", "art", "theatre", "music"]
不使用列表理解的代码
output = []
for name, hobbies in input.items():
for hobby in hobbies:
if hobby not in output:
output.append(hobby)
我的尝试
[hobby for name, hobbies in input.items() for hobby in hobbies if hobby not in ???]
使用一套:
dict = {
"Stefan" : ["running", "engineering", "dancing"],
"Bob" : ["dancing", "art", "theatre"],
"Julia" : ["running", "music", "art"]
}
myset = set()
for _, value in dict.items():
for item in value:
myset.add(item)
print(myset)
这个怎么样:
set(dict['Bob']+dict['Stefan']+dict['Julia'])
>>> set(['art', 'theatre', 'dancing', 'engineering', 'running', 'music'])
或者更好:
dict = {
"Stefan" : ["running", "engineering", "dancing"],
"Bob" : ["dancing", "art", "theatre"],
"Julia" : ["running", "music", "art"]
}
list_ = []
for y in dict.keys():
list_ = list_ + dict[y]
list_ = set(list_)
>>> list_
set(['art', 'theatre', 'dancing', 'engineering', 'running', 'music'])
您可以将 list
函数应用于 list_,就像 list(list_)
应用于 return 列表而不是集合。
您可以使用 set
并设置理解:
{hobby for name, hobbies in input.items() for hobby in hobbies}
作为,我们这里不用name
,所以可以用item.values()
代替:
{hobby for hobbies in input.values() for hobby in hobbies}
如果你真的需要一个列表作为结果,你可以这样做(但请注意,通常你可以毫无问题地使用集合):
list({hobby for hobbies in input.values() for hobby in hobbies})
正如this answer建议的那样:您可以使用唯一性过滤器:
def f7(seq):
seen = set()
seen_add = seen.add
return [x for x in seq if not (x in seen or seen_add(x))]
并调用:
>>> f7(hobby for name, hobbies in input.items() for hobby in hobbies)
['running', 'engineering', 'dancing', 'art', 'theatre', 'music']
我会单独实施 唯一性过滤器,因为设计规则说 "different things should be handled by different classes/methods/components/whatever"。此外,如有必要,您可以简单地重复使用此方法。
另一个优点是 - 如 linked answer 中所写 - 项目的 顺序 得以保留。对于某些应用程序,这可能是必要的。
集和词典是你的朋友:
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']
如果你真的想要一个 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']
此处,s
是副作用的结果,d
是您的原始词典。这里的独特优势是 您可以保留顺序,这与此处的大多数其他答案不同。
Note: This a bad way as it exploits the list-comp and the result is a side effect. Don't do it as a practice, This answer is just to show you that you can achieve it using a list comp alone
列表理解不太适合解决这个问题。我认为集合理解会更好,但由于已经在另一个答案中显示了这一点,我将展示一种使用紧凑的单行代码解决此问题的方法:
list(set(sum(hobbies_dict.values(), [])))
另一个有趣的解决方案是使用按位或运算符作为集合的并集运算符:
from operator import or_
from functools import reduce # Allowed, but unnecessary in Python 2.x
list(reduce(or_, map(set, hobbies_dict.values())))
Or(无意的双关语,我发誓),而不是使用按位或运算符,只需使用 set.union
并将您的值的解压缩集合映射传递给它。无需导入 or_
和 reduce
!这个想法的灵感来自 .
list(set.union(*map(set, hobbies_dict.values())))
还有另一种写法,它更能描述您实际正在做的事情,并且不需要嵌套(双 for
)理解:
output = set.union(*[set(hobbies) for hobbies in input_.values()])
当您表示输入在概念上更合理时,这会变得更好,即使用 set
表示每个人的爱好(因为那里也不应该重复):
input_ = {
"Stefan" : {"running", "engineering", "dancing"},
"Bob" : {"dancing", "art", "theatre"},
"Julia" : {"running", "music", "art"}
}
output = set.union(*input_.values())
我正在尝试编写一个列表理解语句,它只会添加当前不包含在列表中的项目。有没有办法检查当前正在构建的列表中的当前项目?这是一个简短的例子:
输入
{
"Stefan" : ["running", "engineering", "dancing"],
"Bob" : ["dancing", "art", "theatre"],
"Julia" : ["running", "music", "art"]
}
输出
["running", "engineering", "dancing", "art", "theatre", "music"]
不使用列表理解的代码
output = []
for name, hobbies in input.items():
for hobby in hobbies:
if hobby not in output:
output.append(hobby)
我的尝试
[hobby for name, hobbies in input.items() for hobby in hobbies if hobby not in ???]
使用一套:
dict = {
"Stefan" : ["running", "engineering", "dancing"],
"Bob" : ["dancing", "art", "theatre"],
"Julia" : ["running", "music", "art"]
}
myset = set()
for _, value in dict.items():
for item in value:
myset.add(item)
print(myset)
这个怎么样:
set(dict['Bob']+dict['Stefan']+dict['Julia'])
>>> set(['art', 'theatre', 'dancing', 'engineering', 'running', 'music'])
或者更好:
dict = {
"Stefan" : ["running", "engineering", "dancing"],
"Bob" : ["dancing", "art", "theatre"],
"Julia" : ["running", "music", "art"]
}
list_ = []
for y in dict.keys():
list_ = list_ + dict[y]
list_ = set(list_)
>>> list_
set(['art', 'theatre', 'dancing', 'engineering', 'running', 'music'])
您可以将 list
函数应用于 list_,就像 list(list_)
应用于 return 列表而不是集合。
您可以使用 set
并设置理解:
{hobby for name, hobbies in input.items() for hobby in hobbies}
作为name
,所以可以用item.values()
代替:
{hobby for hobbies in input.values() for hobby in hobbies}
如果你真的需要一个列表作为结果,你可以这样做(但请注意,通常你可以毫无问题地使用集合):
list({hobby for hobbies in input.values() for hobby in hobbies})
正如this answer建议的那样:您可以使用唯一性过滤器:
def f7(seq):
seen = set()
seen_add = seen.add
return [x for x in seq if not (x in seen or seen_add(x))]
并调用:
>>> f7(hobby for name, hobbies in input.items() for hobby in hobbies)
['running', 'engineering', 'dancing', 'art', 'theatre', 'music']
我会单独实施 唯一性过滤器,因为设计规则说 "different things should be handled by different classes/methods/components/whatever"。此外,如有必要,您可以简单地重复使用此方法。
另一个优点是 - 如 linked answer 中所写 - 项目的 顺序 得以保留。对于某些应用程序,这可能是必要的。
集和词典是你的朋友:
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']
如果你真的想要一个 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']
此处,s
是副作用的结果,d
是您的原始词典。这里的独特优势是 您可以保留顺序,这与此处的大多数其他答案不同。
Note: This a bad way as it exploits the list-comp and the result is a side effect. Don't do it as a practice, This answer is just to show you that you can achieve it using a list comp alone
列表理解不太适合解决这个问题。我认为集合理解会更好,但由于已经在另一个答案中显示了这一点,我将展示一种使用紧凑的单行代码解决此问题的方法:
list(set(sum(hobbies_dict.values(), [])))
另一个有趣的解决方案是使用按位或运算符作为集合的并集运算符:
from operator import or_
from functools import reduce # Allowed, but unnecessary in Python 2.x
list(reduce(or_, map(set, hobbies_dict.values())))
Or(无意的双关语,我发誓),而不是使用按位或运算符,只需使用 set.union
并将您的值的解压缩集合映射传递给它。无需导入 or_
和 reduce
!这个想法的灵感来自
list(set.union(*map(set, hobbies_dict.values())))
还有另一种写法,它更能描述您实际正在做的事情,并且不需要嵌套(双 for
)理解:
output = set.union(*[set(hobbies) for hobbies in input_.values()])
当您表示输入在概念上更合理时,这会变得更好,即使用 set
表示每个人的爱好(因为那里也不应该重复):
input_ = {
"Stefan" : {"running", "engineering", "dancing"},
"Bob" : {"dancing", "art", "theatre"},
"Julia" : {"running", "music", "art"}
}
output = set.union(*input_.values())