[[1, '34', '44'], [1, '40', '30', '41'], [1, '41', '40', '42'], [1, '42', '41', '43'], [1, '43', '42', '44'], [1, '44', '34', '43']]
我有一份清单清单。我的目的是检查是否有任何一个子列表与其他子列表有任何共同点(不包括要比较的第一个索引对象)。如果它有任何共同点,那么统一这些子列表。
例如,对于这个例子,我的最终答案应该是:
[[1, '34, '44', '40' '30', '41', '42', '43']]
我可以理解我应该将子列表转换为集合,然后使用union()和intersection()操作。但我坚持的是如何比较每个集/子列表。我不能在列表上运行循环并逐个比较每个子列表,因为列表的内容将被修改,这将导致错误。
我想知道的是有没有有效的方法来比较所有子列表(转换为集合)并获得它们的并集?
答案 0 :(得分:21)
itertools模块解决了这个问题:
>>> from itertools import chain
>>> list(set(chain.from_iterable(d)))
[1, '41', '42', '43', '40', '34', '30', '44']
另一种方法是将列表解压缩为 union()的单独参数:
>>> list(set().union(*d))
[1, '41', '42', '43', '40', '34', '30', '44']
后一种方法消除了所有重复项,并且不要求首先将输入转换为集合。此外,它不需要导入。
答案 1 :(得分:16)
>> list(set.union(*map(set, a)))
[1, '44', '30', '42', '43', '40', '41', '34']
(感谢Raymond Hettinger的评论!)
(注意
set.union(*tup)
会解压到
set.union(tup[0], tup[1], ... tup[n - 1])
)
答案 2 :(得分:2)
我个人喜欢reduce
的可读性,并配有简单的条件函数,例如
somelists = [[1, '41', '40', '42'], [1, '42', '41', '43'], [1, '43', '42', '44'], [1, '44', '34', '43']] # your original lists
somesets = map(set,somelists) #your lists as sets
def condition(s1,s2): # condition to apply recursively to the sets
if s1.intersection(s2):
return s1.union(s2)
reduce( condition,somesets)
#{1, '30', '34', '40', '41', '42', '43', '44'}
当然,如果您需要list([reduce(...
我会注意到,这比chain.fromiterable
答案慢3倍。
答案 3 :(得分:1)
@RequestMapping(value = "/users/{userId}/providers/{providerId}/documents/{documentId}/consents/new", method = RequestMethod.GET)
public String initNewConsentForm(@PathVariable("userId") int userId,@PathVariable("providerId") int providerId,@PathVariable("documentId") int documentId, Model model) {
User user = this.clinicService.findUserById(userId);
Provider provider = this.clinicService.findProviderById(providerId);
Document document = this.clinicService.findDocumentById(documentId);
Collection<User> users = this.clinicService.AllUsers();
Consent consent = new Consent();
model.addAttribute("provider",provider);
model.addAttribute("document", document);
model.addAttribute("user", user);
model.addAttribute("users", users);
return "providers/createOrUpdateConsentForm";
}
更新
感谢您的评论
答案 4 :(得分:1)
您可以使用itertools执行此操作。我们假设您的列表有一个变量名A
import itertools
single_list_with_all_values = list(itertools.chain(*A))
single_list_with_all_values.sort()
print set(single_list_with_all_values)
答案 5 :(得分:1)
>>> big = [[1, '34', '44'], [1, '40', '30', '41'], [1, '41', '40', '42'], [1, '42', '41', '43'], [1, '43', '42', '44'], [1, '44', '34', '43']]
>>> set(reduce ( lambda l,a : l + a, big))
set([1, '44', '30', '42', '43', '40', '41', '34'])
如果你真的想要一个列表列表作为最终结果
>>>>[list(set(reduce ( lambda l,a : l + a, big)))]
[[1, '44', '30', '42', '43', '40', '41', '34']]
如果您不喜欢为列表添加重新编码lambda函数:
>>>>[list(set(reduce ( list.__add__, big)))]
[[1, '44', '30', '42', '43', '40', '41', '34']]
编辑:在您建议使用itertools.chain而不是list .__ add__之后,我使用原始海报使用的原始变量为两者运行了一个timeit。
似乎timeit times列出.__ add__大约2.8s,itertools.chain大约3.5秒。
我在这个页面上查了一下是的,你是对的,因为itertools.chain包含一个from_iterable方法,可以提供巨大的性能提升。请参阅下面的列表.__ add __,itertools.chain和itertools.chain.from_iterable。
>>> timeit.timeit("[list(set(reduce ( list.__add__, big)))]", setup="big = [ [10,20,30,40] for ele in range(10000)]", number=30)
16.051744650801993
>>> timeit.timeit("[list(set(reduce ( itertools.chain, big)))]", setup="big = [ [10,20,30,40] for ele in range(10000)]", number=30)
54.721315866467194
>>> timeit.timeit("list(set(itertools.chain.from_iterable(big)))", setup="big = [ [10,20,30,40] for ele in range(10000)]", number=30)
0.040056066849501804
非常感谢您的建议:)
答案 6 :(得分:0)
from functools import reduce
out = list(reduce(set.union, iterable))
,只要iterable
的至少第一个元素是集合即可。否则,
out = list(reduce(set.union, iterable[1:], set(iterable[0])))