简体   繁体   English

查找两个嵌套列表的交集?

[英]Find intersection of two nested lists?

I know how to get an intersection of two flat lists:我知道如何获得两个平面列表的交集:

b1 = [1,2,3,4,5,9,11,15]
b2 = [4,5,6,7,8]
b3 = [val for val in b1 if val in b2]

or要么

def intersect(a, b):
    return list(set(a) & set(b))
 
print intersect(b1, b2)

But when I have to find intersection for nested lists then my problems starts:但是当我必须为嵌套列表找到交集时,我的问题就开始了:

c1 = [1, 6, 7, 10, 13, 28, 32, 41, 58, 63]
c2 = [[13, 17, 18, 21, 32], [7, 11, 13, 14, 28], [1, 5, 6, 8, 15, 16]]

In the end I would like to receive:最后我想收到:

c3 = [[13,32],[7,13,28],[1,6]]

Can you guys give me a hand with this?你们能帮我一下吗?

Related有关的

You don't need to define intersection.您不需要定义交集。 It's already a first-class part of set.已经是布景的一流部分了。

>>> b1 = [1,2,3,4,5,9,11,15]
>>> b2 = [4,5,6,7,8]
>>> set(b1).intersection(b2)
set([4, 5])

If you want:如果你想:

c1 = [1, 6, 7, 10, 13, 28, 32, 41, 58, 63]
c2 = [[13, 17, 18, 21, 32], [7, 11, 13, 14, 28], [1, 5, 6, 8, 15, 16]]
c3 = [[13, 32], [7, 13, 28], [1,6]]

Then here is your solution for Python 2:那么这是 Python 2 的解决方案:

c3 = [filter(lambda x: x in c1, sublist) for sublist in c2]

In Python 3 filter returns an iterable instead of list , so you need to wrap filter calls with list() :在 Python 3 中, filter返回一个可迭代对象而不是list ,因此您需要使用list()包装filter调用:

c3 = [list(filter(lambda x: x in c1, sublist)) for sublist in c2]

Explanation:解释:

The filter part takes each sublist's item and checks to see if it is in the source list c1.过滤器部分获取每个子列表的项目并检查它是否在源列表 c1 中。 The list comprehension is executed for each sublist in c2.对 c2 中的每个子列表执行列表理解。

For people just looking to find the intersection of two lists, the Asker provided two methods:对于只想找到两个列表的交集的人,Asker 提供了两种方法:

 b1 = [1,2,3,4,5,9,11,15] b2 = [4,5,6,7,8] b3 = [val for val in b1 if val in b2]

and

def intersect(a, b): return list(set(a) & set(b)) print intersect(b1, b2)

But there is a hybrid method that is more efficient, because you only have to do one conversion between list/set, as opposed to three:但是有一种混合方法更有效,因为你只需要在列表/集合之间进行一次转换,而不是三个:

b1 = [1,2,3,4,5]
b2 = [3,4,5,6]
s2 = set(b2)
b3 = [val for val in b1 if val in s2]

This will run in O(n), whereas his original method involving list comprehension will run in O(n^2)这将在 O(n) 中运行,而他涉及列表理解的原始方法将在 O(n^2) 中运行

The functional approach:功能方法:

input_list = [[1, 2, 3, 4, 5], [2, 3, 4, 5, 6], [3, 4, 5, 6, 7]]

result = reduce(set.intersection, map(set, input_list))

and it can be applied to the more general case of 1+ lists它可以应用于 1+ 列表的更一般情况

Pure list comprehension version纯列表理解版

>>> c1 = [1, 6, 7, 10, 13, 28, 32, 41, 58, 63]
>>> c2 = [[13, 17, 18, 21, 32], [7, 11, 13, 14, 28], [1, 5, 6, 8, 15, 16]]
>>> c1set = frozenset(c1)

Flatten variant:展平变体:

>>> [n for lst in c2 for n in lst if n in c1set]
[13, 32, 7, 13, 28, 1, 6]

Nested variant:嵌套变体:

>>> [[n for n in lst if n in c1set] for lst in c2]
[[13, 32], [7, 13, 28], [1, 6]]

The & operator takes the intersection of two sets. & 运算符取两个集合的交集。

{1, 2, 3} & {2, 3, 4}
Out[1]: {2, 3}

A pythonic way of taking the intersection of 2 lists is:获取 2 个列表的交集的 pythonic 方法是:

[x for x in list1 if x in list2]

You should flatten using this code ( taken from http://kogs-www.informatik.uni-hamburg.de/~meine/python_tricks ), the code is untested, but I'm pretty sure it works:您应该使用此代码(取自http://kogs-www.informatik.uni-hamburg.de/~meine/python_tricks )进行展平,该代码未经测试,但我很确定它可以工作:


def flatten(x):
    """flatten(sequence) -> list

    Returns a single, flat list which contains all elements retrieved
    from the sequence and all recursively contained sub-sequences
    (iterables).

    Examples:
    >>> [1, 2, [3,4], (5,6)]
    [1, 2, [3, 4], (5, 6)]
    >>> flatten([[[1,2,3], (42,None)], [4,5], [6], 7, MyVector(8,9,10)])
    [1, 2, 3, 42, None, 4, 5, 6, 7, 8, 9, 10]"""

    result = []
    for el in x:
        #if isinstance(el, (list, tuple)):
        if hasattr(el, "__iter__") and not isinstance(el, basestring):
            result.extend(flatten(el))
        else:
            result.append(el)
    return result

After you had flattened the list, you perform the intersection in the usual way:展平列表后,以通常的方式执行交集:


c1 = [1, 6, 7, 10, 13, 28, 32, 41, 58, 63]
c2 = [[13, 17, 18, 21, 32], [7, 11, 13, 14, 28], [1, 5, 6, 8, 15, 16]]

def intersect(a, b):
     return list(set(a) & set(b))

print intersect(flatten(c1), flatten(c2))

Since intersect was defined, a basic list comprehension is enough:由于定义了intersect ,基本的列表理解就足够了:

>>> c3 = [intersect(c1, i) for i in c2]
>>> c3
[[32, 13], [28, 13, 7], [1, 6]]

Improvement thanks to S. Lott's remark and TM.'s associated remark:由于 S. Lott 的评论和 TM 的相关评论而得到改进:

>>> c3 = [list(set(c1).intersection(i)) for i in c2]
>>> c3
[[32, 13], [28, 13, 7], [1, 6]]

Given:鉴于:

> c1 = [1, 6, 7, 10, 13, 28, 32, 41, 58, 63]

> c2 = [[13, 17, 18, 21, 32], [7, 11, 13, 14, 28], [1, 5, 6, 8, 15, 16]]

I find the following code works well and maybe more concise if using set operation:我发现下面的代码运行良好,如果使用 set 操作可能更简洁:

> c3 = [list(set(f)&set(c1)) for f in c2] 

It got:它得到了:

> [[32, 13], [28, 13, 7], [1, 6]]

If order needed:如果需要订购:

> c3 = [sorted(list(set(f)&set(c1))) for f in c2] 

we got:我们有:

> [[13, 32], [7, 13, 28], [1, 6]]

By the way, for a more python style, this one is fine too:顺便说一下,对于更多 python 样式,这个也可以:

> c3 = [ [i for i in set(f) if i in c1] for f in c2]

I don't know if I am late in answering your question.我不知道我是否迟迟不能回答你的问题。 After reading your question I came up with a function intersect() that can work on both list and nested list.阅读您的问题后,我想出了一个 function intersect() 可以在列表和嵌套列表上工作。 I used recursion to define this function, it is very intuitive.我用递归定义了这个function,很直观。 Hope it is what you are looking for:希望这是你要找的:

def intersect(a, b):
    result=[]
    for i in b:
        if isinstance(i,list):
            result.append(intersect(a,i))
        else:
            if i in a:
                 result.append(i)
    return result

Example:例子:

>>> c1 = [1, 6, 7, 10, 13, 28, 32, 41, 58, 63]
>>> c2 = [[13, 17, 18, 21, 32], [7, 11, 13, 14, 28], [1, 5, 6, 8, 15, 16]]
>>> print intersect(c1,c2)
[[13, 32], [7, 13, 28], [1, 6]]

>>> b1 = [1,2,3,4,5,9,11,15]
>>> b2 = [4,5,6,7,8]
>>> print intersect(b1,b2)
[4, 5]

Do you consider [1,2] to intersect with [1, [2]] ?你认为[1,2][1, [2]]相交吗? That is, is it only the numbers you care about, or the list structure as well?也就是说,它只是您关心的数字,还是列表结构?

If only the numbers, investigate how to "flatten" the lists, then use the set() method.如果只有数字,研究如何“展平”列表,然后使用set()方法。

I was also looking for a way to do it, and eventually it ended up like this:我也一直在寻找一种方法来做到这一点,最终结果是这样的:

def compareLists(a,b):
    removed = [x for x in a if x not in b]
    added = [x for x in b if x not in a]
    overlap = [x for x in a if x in b]
    return [removed,added,overlap]

To define intersection that correctly takes into account the cardinality of the elements use Counter :要定义正确考虑元素基数的交集,请使用Counter

from collections import Counter

>>> c1 = [1, 2, 2, 3, 4, 4, 4]
>>> c2 = [1, 2, 4, 4, 4, 4, 5]
>>> list((Counter(c1) & Counter(c2)).elements())
[1, 2, 4, 4, 4]
c1 = [1, 6, 7, 10, 13, 28, 32, 41, 58, 63]

c2 = [[13, 17, 18, 21, 32], [7, 11, 13, 14, 28], [1, 5, 6, 8, 15, 16]]

c3 = [list(set(c2[i]).intersection(set(c1))) for i in xrange(len(c2))]

c3
->[[32, 13], [28, 13, 7], [1, 6]]

We can use set methods for this:我们可以为此使用 set 方法:

c1 = [1, 6, 7, 10, 13, 28, 32, 41, 58, 63]
c2 = [[13, 17, 18, 21, 32], [7, 11, 13, 14, 28], [1, 5, 6, 8, 15, 16]]

   result = [] 
   for li in c2:
       res = set(li) & set(c1)
       result.append(list(res))

   print result
# Problem:  Given c1 and c2:
c1 = [1, 6, 7, 10, 13, 28, 32, 41, 58, 63]
c2 = [[13, 17, 18, 21, 32], [7, 11, 13, 14, 28], [1, 5, 6, 8, 15, 16]]
# how do you get c3 to be [[13, 32], [7, 13, 28], [1, 6]] ?

Here's one way to set c3 that doesn't involve sets:这是设置不涉及集合的c3的一种方法:

c3 = []
for sublist in c2:
    c3.append([val for val in c1 if val in sublist])

But if you prefer to use just one line, you can do this:但是如果你更喜欢只使用一行,你可以这样做:

c3 = [[val for val in c1 if val in sublist]  for sublist in c2]

It's a list comprehension inside a list comprehension, which is a little unusual, but I think you shouldn't have too much trouble following it.它是列表推导中的列表推导,这有点不寻常,但我认为您理解它应该不会有太多麻烦。

c1 = [1, 6, 7, 10, 13, 28, 32, 41, 58, 63]
c2 = [[13, 17, 18, 21, 32], [7, 11, 13, 14, 28], [1, 5, 6, 8, 15, 16]]
c3 = [list(set(i) & set(c1)) for i in c2]
c3
[[32, 13], [28, 13, 7], [1, 6]]

For me this is very elegant and quick way to to it:)对我来说,这是一种非常优雅和快速的方法:)

flat list can be made through reduce easily.平面列表可以通过reduce轻松制作。

All you need to use initializer - third argument in the reduce function.您只需要使用初始化程序- reduce function 中的第三个参数。

reduce(
   lambda result, _list: result.append(
       list(set(_list)&set(c1)) 
     ) or result, 
   c2, 
   [])

Above code works for both python2 and python3, but you need to import reduce module as from functools import reduce .上面的代码适用于 python2 和 python3,但您需要导入 reduce 模块,如from functools import reduce Refer below link for details.有关详细信息,请参阅以下链接。

Simple way to find difference and intersection between iterables查找可迭代对象之间差异和交集的简单方法

Use this method if repetition matters如果重复很重要,请使用此方法

from collections import Counter

def intersection(a, b):
    """
    Find the intersection of two iterables

    >>> intersection((1,2,3), (2,3,4))
    (2, 3)

    >>> intersection((1,2,3,3), (2,3,3,4))
    (2, 3, 3)

    >>> intersection((1,2,3,3), (2,3,4,4))
    (2, 3)

    >>> intersection((1,2,3,3), (2,3,4,4))
    (2, 3)
    """
    return tuple(n for n, count in (Counter(a) & Counter(b)).items() for _ in range(count))

def difference(a, b):
    """
    Find the symmetric difference of two iterables

    >>> difference((1,2,3), (2,3,4))
    (1, 4)

    >>> difference((1,2,3,3), (2,3,4))
    (1, 3, 4)

    >>> difference((1,2,3,3), (2,3,4,4))
    (1, 3, 4, 4)
    """
    diff = lambda x, y: tuple(n for n, count in (Counter(x) - Counter(y)).items() for _ in range(count))
    return diff(a, b) + diff(b, a)
from random import *

a = sample(range(0, 1000), 100)
b = sample(range(0, 1000), 100)
print(a)
print(b)
print(set(a).intersection(set(b)))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM