दो नेस्टेड सूचियों का प्रतिच्छेदन ज्ञात करें?


468

मुझे पता है कि दो फ्लैट सूचियों का प्रतिच्छेदन कैसे प्राप्त करें:

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]

या

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

print intersect(b1, b2)

लेकिन जब मुझे नेस्टेड सूचियों के लिए चौराहा ढूंढना होता है तो मेरी समस्याएं शुरू हो जाती हैं:

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

क्या तुम लोग मुझे इसके साथ हाथ दे सकते हो?

सम्बंधित


C1 प्रतिच्छेदन c2 के लिए आपका चौराहा क्या होगा? क्या आप जानना चाहते हैं कि क्या c1 c2 में है? या क्या आप c1 में उन सभी तत्वों को खोजना चाहते हैं जो c2 में कहीं भी दिखाई देते हैं?
ब्रायन आर। बॉन्डी

पढ़ें यह और दुभाषिया में खेलते हैं।
पिथिकोस

जवाबों:


177

अगर तुम चाहते हो:

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

फिर यहाँ अजगर 2 के लिए आपका समाधान है:

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

पायथन 3 के filterबजाय एक पुनरावृत्ति देता है list, इसलिए आपको इसके filterसाथ कॉल लपेटने की आवश्यकता है list():

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

स्पष्टीकरण:

फ़िल्टर हिस्सा प्रत्येक सबलिस्ट की वस्तु लेता है और यह देखने के लिए जांचता है कि क्या यह स्रोत सूची c1 में है। सूची बोध को c2 में प्रत्येक सबलिस्ट के लिए निष्पादित किया जाता है।


35
आप filter(set(c1).__contains__, sublist)दक्षता के लिए उपयोग कर सकते हैं । btw, इस समाधान का लाभ यह है कि filter()तार और टुपल्स प्रकारों को संरक्षित करता है।
jfs

3
मुझे यह तरीका पसंद है, लेकिन मैं अपनी परिणामी सूची में रिक्त '' हूं
जोनाथन ओंग

मैंने पायथन 3 के कंपोजर्स को यहां जोड़ा, क्योंकि मैं इसे पायथन 3 प्रश्न के
डूप के

9
यह नेस्टेड कॉम्प्रिहेंशन के साथ बेहतर IMO पढ़ता है:c3 = [[x for x in sublist if x in c1] for sublist in c2]
एरिक

894

आपको चौराहे को परिभाषित करने की आवश्यकता नहीं है। यह पहले से ही सेट का प्रथम श्रेणी का हिस्सा है।

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

3
क्या यह रूपांतरण के कारण लंबोदर की तुलना में धीमा होगा?
सिरो सेंटिल्ली 郝海东 冠状 iro i 法轮功 '

32
@ S.Lott, कुछ भी गलत है set(b1) & set(b2)? IMO ऑपरेटर का उपयोग करने के लिए इसका क्लीनर।
gwg

4
इसके अलावा, setकोड के उपयोग से कोड होगा जो परिमाण के आदेशों को तेजी से बढ़ाएगा। : यहाँ एक नमूना benchmark® है gist.github.com/andersonvom/4d7e551b4c0418de3160
andersonvom

5
केवल तभी काम करता है जब परिणाम का आदेश न हो।
बोरबाग

7
तो ... यह जवाब किसी भी तरह से सवाल का जवाब नहीं देता है, है ना? क्योंकि यह अब नेस्टेड सूचियों के साथ काम करता है।
Mayou36

60

दो सूचियों के प्रतिच्छेदन को खोजने के लिए देख रहे लोगों के लिए, प्रश्नकर्ता ने दो विधियाँ प्रदान की हैं:

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]

तथा

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

print intersect(b1, b2)

लेकिन एक संकर विधि है जो अधिक कुशल है, क्योंकि आपको केवल तीन के विपरीत सूची / सेट के बीच एक रूपांतरण करना है:

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

यह O (n) में चलेगा, जबकि सूची बोध से संबंधित उसकी मूल विधि O (n ^ 2) में चलेगी


ओ (एन) में "अगर वैल इन एस 2" चलता है, तो प्रस्तावित कोड स्निपेट जटिलता भी ओ (एन ^ 2) है
रेमेनो

8
"वैल इन s2" का औसत मामला wiki.python.org/moin/TimeComplexity#set के अनुसार O (1) है - इस प्रकार n संचालन पर अपेक्षित समय O (n) है (चाहे सबसे खराब समय O हो) n) या O (n ^ 2) इस बात पर निर्भर करता है कि यह औसत मामला एक परिशोधन समय का प्रतिनिधित्व करता है या नहीं, लेकिन व्यवहार में यह बहुत महत्वपूर्ण नहीं है)।
डी कोएट्ज़ी

2
रनटाइम O (N) इसलिए नहीं है क्योंकि यह amortized है, बल्कि इसलिए कि सेट की सदस्यता औसत O (1) में है (उदाहरण के लिए हैश टेबल का उपयोग करते समय), यह बड़ा अंतर है, उदाहरण के लिए क्योंकि amortized समय की गारंटी है।
miroB

28

कार्यात्मक दृष्टिकोण:

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

और इसे 1+ सूचियों के सामान्य मामले में लागू किया जा सकता है


खाली इनपुट सूची की अनुमति देने के लिए set(*input_list[:1]).intersection(*input_list[1:]):। Iterator संस्करण ( it = iter(input_list)) reduce(set.intersection, it, set(next(it, []))):। दोनों संस्करण को सेट करने के लिए सभी इनपुट सूचियों को बदलने की आवश्यकता नहीं है। उत्तरार्द्ध अधिक स्मृति कुशल है।
jfs

इसका from functools import reduceउपयोग पाइथन 3 में उपयोग करने के लिए करें । या बेहतर अभी तक, एक स्पष्ट forलूप का उपयोग करें ।
त्रियोगोनिमा

27

शुद्ध सूची बोध संस्करण

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

चपटा रूप:

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

नेस्टेड वेरिएंट:

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

20

& ऑपरेटर दो सेट का प्रतिच्छेदन लेता है।

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

ठीक है, लेकिन यह विषय सूचियों के लिए है!
राफा ०37०

3
दो सूचियों के प्रतिच्छेदन का परिणाम एक सेट है इसलिए यह उत्तर पूरी तरह से मान्य है।
shrewmouse

सूची में डुप्लिकेट मान हो सकता है लेकिन सेट नहीं है।
diewland

13

2 सूचियों के प्रतिच्छेदन लेने का एक पायथोनिक तरीका है:

[x for x in list1 if x in list2]

2
यह प्रश्न नेस्टेड सूचियों के बारे में है। आपका उत्तर प्रश्न का उत्तर नहीं देता है।
थॉमस

8

आपको इस कोड ( 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

सूची को चपटा करने के बाद, आप सामान्य तरीके से चौराहे का प्रदर्शन करते हैं:


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
यह एक अच्छा सा समतल कोड जियो है, लेकिन यह सवाल का जवाब नहीं देता है। पूछने वाला विशेष रूप से [[13,32], [7,13,28], [1,6]] रूप में परिणाम की उम्मीद करता है।
रोब यंग

8

चूंकि intersectपरिभाषित किया गया था, एक बुनियादी सूची समझ पर्याप्त है:

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

एस। लोट्ट की टिप्पणी और टीएम से जुड़ी टिप्पणी के लिए सुधार:

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

5

दिया हुआ:

> 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(f)&set(c1)) for f in c2] 

इसे मिला:

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

यदि आवश्यक आदेश:

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

हमें मिला:

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

वैसे, अधिक अजगर शैली के लिए, यह ठीक है:

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

3

मुझे नहीं पता कि मुझे आपके प्रश्न का उत्तर देने में देर हो रही है। आपके प्रश्न को पढ़ने के बाद मैं एक फंक्शन चौराहे () के साथ आया जो सूची और नेस्टेड सूची दोनों पर काम कर सकता है। मैंने इस फ़ंक्शन को परिभाषित करने के लिए रिकर्सन का उपयोग किया, यह बहुत सहज है। आशा है कि आप इसे देख रहे हैं:

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

उदाहरण:

>>> 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]साथ प्रतिच्छेद करने पर विचार करते हैं[1, [2]] ? यही है, क्या यह केवल उन संख्याओं के बारे में है जिनकी आप परवाह करते हैं, या सूची संरचना भी?

यदि केवल संख्याएं, जांच करें कि सूचियों को "समतल" कैसे किया जाए, तो set()विधि का उपयोग करें ।


मैं सूचियों की संरचना को अपरिवर्तित छोड़ना चाहूंगा।
elfuego1

1

मैं भी इसे करने का तरीका ढूंढ रहा था, और आखिरकार यह इस तरह समाप्त हो गया:

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 का उपयोग नहीं कर रहे हैं तो ये सरल एक लाइनर हैं जो मैं भी करूंगा।
वध

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

हम इसके लिए निर्धारित विधियों का उपयोग कर सकते हैं:

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

चौराहे को परिभाषित करने के लिए जो तत्वों के उपयोग की कार्डिनैलिटी को सही ढंग से ध्यान में रखता है 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]] ?

यहां सेट करने का एक तरीका है c3जिसमें सेट शामिल नहीं हैं:

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

लेकिन अगर आप सिर्फ एक लाइन का उपयोग करना पसंद करते हैं, तो आप यह कर सकते हैं:

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

यह एक सूची समझ के अंदर एक सूची की समझ है, जो थोड़ा असामान्य है, लेकिन मुझे लगता है कि आपको इसके बाद बहुत अधिक परेशानी नहीं होनी चाहिए।


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

मेरे लिए यह बहुत ही सुंदर और त्वरित तरीका है :)


0

फ्लैट सूची reduceआसानी से बनाई जा सकती है ।

आपको फ़ंक्शन में शुरुआती - तीसरे तर्क का उपयोग करने की आवश्यकता है reduce

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

उपरोक्त कोड python2 और python3 दोनों के लिए काम करता है, लेकिन आपको मॉड्यूल को कम करने की आवश्यकता है from functools import reduce। विवरण के लिए नीचे दिए गए लिंक का संदर्भ लें।


-1

पुनरावृत्तियों के बीच अंतर और प्रतिच्छेदन खोजने का सरल तरीका

अगर दोहराव मायने रखता है तो इस विधि का उपयोग करें

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)
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.