سؤال

أنا أعرف كيفية الحصول على تقاطع اثنين شقة القوائم:

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 = [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.

نصائح أخرى

لا تحتاج إلى تحديد التقاطع.إنها بالفعل جزء من الدرجة الأولى في المجموعة.

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

بالنسبة للأشخاص الذين يبحثون فقط عن تقاطع قائمتين، قدم السائل طريقتين:

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)

النهج الوظيفي:

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+

نسخة فهم القائمة النقية

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

المعامل & يأخذ تقاطع مجموعتين.

{1, 2, 3} & {2, 3, 4} من[1]:{2, 3}

الطريقة الثعبانية لأخذ تقاطع قائمتين هي:

[x for x in list1 if x in list2]

يجب عليك التسطيح باستخدام هذا الرمز (مأخوذ من 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))

منذ intersect تم تعريفه، فهم القائمة الأساسية يكفي:

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

تحسن بفضل S.ملاحظة لوت وملاحظة TM المرتبطة بها:

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

منح:

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

هل تعتبر [1,2] للتقاطع مع [1, [2]]؟أي هل هي الأرقام التي تهمك فقط أم بنية القائمة أيضًا؟

إذا كانت الأرقام فقط، فتحقق من كيفية "تسوية" القوائم، ثم استخدم set() طريقة.

ولا أعلم إذا تأخرت في الرد على سؤالك.بعد قراءة سؤالك، توصلت إلى وظيفة intersect() يمكنها العمل على كل من القائمة والقائمة المتداخلة.لقد استخدمت العودية لتحديد هذه الوظيفة، فهي بديهية للغاية.نأمل أن يكون ما تبحث عنه:

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]

كنت أبحث أيضًا عن طريقة للقيام بذلك، وفي النهاية انتهى الأمر على النحو التالي:

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]

تحديد التقاطع بشكل صحيح يأخذ في الاعتبار أصالة العناصر المستخدمة 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]]

يمكننا استخدام طرق محددة لهذا:

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

إليك طريقة واحدة للضبط 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]

إنها عبارة عن فهم قائمة داخل قائمة فهم، وهو أمر غير معتاد بعض الشيء، لكنني أعتقد أنه لا ينبغي أن تواجه الكثير من المتاعب في متابعته.

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

بالنسبة لي هذه طريقة أنيقة جدًا وسريعة لذلك :)

يمكن عمل قائمة مسطحة من خلال reduce بسهولة.

كل ما تحتاج إلى استخدامه مُهيئ - الحجة الثالثة في reduce وظيفة.

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

يعمل الكود أعلاه مع كل من python2 وpython3، لكنك تحتاج إلى استيراد وحدة التخفيض كـ from functools import reduce.راجع الرابط أدناه للحصول على التفاصيل.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top