İki iç içe listenin kesişimini mi buldunuz?


468

İki düz listenin kesişimini nasıl alacağımı biliyorum:

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]

veya

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

print intersect(b1, b2)

Ama iç içe listeler için kavşak bulmak zorunda kaldığımda sorunlarım başlar:

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

Sonunda almak istiyorum:

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

Bu konuda bana yardım edebilir misiniz?

İlişkili


C1 kesişimi c2 için kesişiminiz ne olurdu? Sadece c1'in c2'de olup olmadığını bulmak ister misiniz? Yoksa c1'de c2'de herhangi bir yerde görünen tüm öğeleri mi bulmak istiyorsunuz?
Brian R. Bondy

Bunu okuyun ve yorumlayıcıda oynayın.
Pithikos

Yanıtlar:


177

Eğer istersen:

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

O halde Python 2 için çözümünüz:

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

Python 3'te filterbunun yerine bir yinelenebilir döndürür list, bu nedenle filteraramaları aşağıdakilerle sarmanız gerekir list():

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

Açıklama:

Filtre kısmı, her bir alt listenin öğesini alır ve c1 kaynak listesinde olup olmadığını kontrol eder. Liste kavrama c2'deki her bir alt liste için yürütülür.


35
filter(set(c1).__contains__, sublist)Verimlilik için kullanabilirsiniz . btw, bu çözümün avantajı filter()telleri ve tuples tiplerini korumaktır.
jfs

3
Bu yöntemi seviyorum, ancak sonuç listemde boş kalıyorum ''
Jonathan Ong

Buraya Python 3 uyumlu ekledim, çünkü bunu bir Python 3 sorusunun bir dupe'si için bir dupe hedefi olarak kullanıyorum
Antti Haapala

9
Bu yuvalanmış kavrayışları ile daha iyi IMO okur:c3 = [[x for x in sublist if x in c1] for sublist in c2]
Eric

894

Kavşağı tanımlamanız gerekmez. Zaten setin birinci sınıf bir parçası.

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

3
Ayarlanan dönüşüm nedeniyle bu lambdadan daha yavaş olacak mı?
Ciro Santilli 法轮功 冠状 病 六四 事件 法轮功

32
@ S.Lott, sorun set(b1) & set(b2)mu var ? Operatörü kullanmak için temizleyici IMO.
gwg

4
Ayrıca, kullanmak setbüyüklük sırası daha hızlı olan koda yol açacaktır. İşte bir benchmark® örneği: gist.github.com/andersonvom/4d7e551b4c0418de3160
andersonvom

5
Yalnızca sonucun sipariş edilmesi gerekmiyorsa çalışır.
Borbag

7
Yani ... bu cevap hiçbir şekilde soruyu cevaplamıyor, değil mi? Çünkü bu artık iç içe listelerle çalışıyor.
Mayou36

60

İki listenin kesişimini bulmak isteyen insanlar için Asker iki yöntem sağladı:

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]

ve

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

print intersect(b1, b2)

Ancak daha verimli olan karma bir yöntem var, çünkü üçün aksine liste / set arasında yalnızca bir dönüşüm yapmanız gerekiyor:

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

Bu liste O (n) 'de, liste kavrayışı içeren orijinal yöntemi O (n ^ 2)' de çalışacaktır.


"Val in s2", O (N) olarak çalıştığından, önerilen kod snippet karmaşıklığı da O (n ^ 2)
Romeno

8
Wiki.python.org/moin/TimeComplexity#set'e göre ortalama "val in s2" durumu O (1) ' dir - bu nedenle n işlemde beklenen süre O (n)' dir (en kötü durum süresi O ( n) veya O (n ^ 2), bu ortalama vakanın itfa edilmiş bir zamanı temsil edip etmediğine bağlıdır, ancak bu pratikte çok önemli değildir).
D Coetzee

2
Çalışma zamanı O (N) 'dir, çünkü amortismana tabi değildir, ancak set üyeliği ortalama O (1) olduğu için (örneğin hash tablosu kullanılırken), örneğin itfa edilmiş zaman garanti edildiği için büyük farktır.
miroB

28

İşlevsel yaklaşım:

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

ve 1 + listelerin daha genel durumuna uygulanabilir


Boş giriş listesini izin vermek: set(*input_list[:1]).intersection(*input_list[1:]). Yineleyici sürümü ( it = iter(input_list)): reduce(set.intersection, it, set(next(it, []))). Her iki sürümün de tüm giriş listelerini sete dönüştürmesi gerekmez. İkincisi bellekte daha verimlidir.
jfs

Kullanım from functools import reduce, daha iyisi Python 3. Veya kullanmak açık kullanmak fordöngü.
TrigonaMinima

27

Saf liste anlama sürümü

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

Değişkeni düzleştir:

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

İç içe varyant:

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

20

& İşleci iki kümenin kesişimini alır.

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

Güzel, ama bu konu listeler için!
Rafa0809

3
İki listenin kesişmesinin sonucu bir kümedir, bu nedenle bu cevap mükemmel şekilde geçerlidir.
shrewmouse

Liste yinelenen değer içerebilir ancak kümeler içermez.
diewland

13

2 listenin kesişimini almanın pythonic bir yolu:

[x for x in list1 if x in list2]

2
Bu soru iç içe listelerle ilgilidir. Cevabınız soruya cevap vermiyor.
Thomas

8

Bu kodu ( http://kogs-www.informatik.uni-hamburg.de/~meine/python_tricks adresinden alınmış ) kullanarak düzleştirmelisiniz , kod test edilmemiştir, ancak çalıştığından eminim:


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

Listeyi düzleştirdikten sonra, kavşağı normal şekilde gerçekleştirirsiniz:


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

2
Bu, Geo kodunu biraz düzleştiriyor, ancak soruyu cevaplamıyor. Asker sonucu [[13,32], [7,13,28], [1,6]] şeklinde beklemektedir.
Rob Young

8

intersectTanımlandığından beri , temel bir liste kavraması yeterlidir:

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

S. Lott'ın açıklaması ve TM.'nin ilgili açıklaması sayesinde iyileştirme:

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

5

Verilen:

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

Ben set kodu kullanarak aşağıdaki kodu iyi çalışır ve belki daha özlü buluyorum:

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

Var:

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

Sipariş gerekiyorsa:

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

aldık:

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

Bu arada, daha python tarzı için, bu da iyi:

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

3

Sorunuzu cevaplamakta gecikip geçmediğimi bilmiyorum. Sorunuzu okuduktan sonra hem liste hem de iç içe liste üzerinde çalışabilecek bir intersect () işlevi buldum. Bu işlevi tanımlamak için özyineleme kullandım, çok sezgisel. Umarım aradığın şey budur:

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

Misal:

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

2

[1,2]İle kesişmeyi düşünüyor musun[1, [2]] ? Yani, sadece önem verdiğiniz sayılar mı yoksa liste yapısı da mı?

Yalnızca sayılar varsa, listelerin nasıl "düzleştirileceğini" araştırın, sonra set()yöntemi kullanın .


Listelerin yapısını değiştirmeden bırakmak istiyorum.
elfuego1

1

Ayrıca bunu yapmanın bir yolunu arıyordum ve sonunda bu şekilde sona erdi:

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]

Set.intersection kullanmıyorsanız, bu basit bir astar da benim yapacağım şeydir.
slaughter98

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

0

Bunun için ayarlanmış yöntemleri kullanabiliriz:

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

0

Elemanların temel özelliklerini dikkate alan kavşağı tanımlamak için 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]

0
# 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]] ?

c3Setleri içermeyen ayarlamanın bir yolu :

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

Ancak yalnızca bir satır kullanmayı tercih ederseniz, bunu yapabilirsiniz:

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

Bu bir liste kavrama içinde bir liste kavrama, ki bu biraz alışılmadık, ama bence bunu takip etmekte çok fazla sorun yaşamamanız gerekir.


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

Benim için bu çok zarif ve hızlı bir yol :)


0

düz liste reducekolayca yapılabilir.

Tek yapmanız gereken işlevde başlatıcı - üçüncü argüman kullanmak reduce.

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

Yukarıdaki kod hem python2 hem de python3 için çalışır, ancak azaltma modülünü olarak içe aktarmanız gerekir from functools import reduce. Ayrıntılar için aşağıdaki bağlantıya bakın.


-1

Tekrarlanabilirler arasındaki farkı ve kavşağı bulmanın kolay yolu

Tekrarlama önemliyse bu yöntemi kullanın

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)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.