python中的多组联盟

时间:2015-06-11 07:07:43

标签: python list python-3.x set-union

[[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()操作。但我坚持的是如何比较每个集/子列表。我不能在列表上运行循环并逐个比较每个子列表,因为列表的内容将被修改,这将导致错误。

我想知道的是有没有有效的方法来比较所有子列表(转换为集合)并获得它们的并集?

7 个答案:

答案 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)

使用unpacking operator *

>> 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])))