Ich weiß, wie man eine Schnittmenge von zwei flachen Listen erhält:
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]
oder
def intersect(a, b):
return list(set(a) & set(b))
print intersect(b1, b2)
Wenn ich für verschachtelte Listen Schnittpunkte finden muss, beginnen meine Probleme:
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]]
Am Ende würde ich gerne erhalten:
c3 = [[13,32],[7,13,28],[1,6]]
Können Sie mir dabei helfen?
Falls Sie es wollen:
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]]
Hier ist Ihre Lösung für Python 2:
c3 = [filter(lambda x: x in c1, sublist) for sublist in c2]
In Python 3 gibt filter
eine iterable statt list
zurück, sodass Sie filter
-Aufrufe mit list()
:
c3 = [list(filter(lambda x: x in c1, sublist)) for sublist in c2]
Erklärung:
Der Filterteil nimmt die Elemente jeder Unterliste und prüft, ob sie in der Quellliste c1 enthalten sind. .__ Das Listenverständnis wird für jede Unterliste in c2 ausgeführt.
Sie müssen keine Kreuzung definieren. Es ist bereits ein erstklassiger Teil des Sets.
>>> b1 = [1,2,3,4,5,9,11,15]
>>> b2 = [4,5,6,7,8]
>>> set(b1).intersection(b2)
set([4, 5])
Für Leute, die nur nach dem Schnittpunkt zweier Listen suchen, stellte der Asker zwei Methoden zur Verfügung:
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]
und
def intersect(a, b): return list(set(a) & set(b)) print intersect(b1, b2)
Es gibt jedoch eine Hybridmethode, die effizienter ist, da Sie nur eine Konvertierung zwischen Liste/Satz und nicht nur drei Konvertierungen durchführen müssen:
b1 = [1,2,3,4,5]
b2 = [3,4,5,6]
s2 = set(b2)
b3 = [val for val in b1 if val in s2]
Dies wird in O (n) ausgeführt, während seine ursprüngliche Methode, die das Listenverständnis umfasst, in O (n ^ 2) ausgeführt wird.
Der funktionale Ansatz:
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))
und es kann auf den allgemeineren Fall von 1+ Listen angewendet werden
>>> 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)
Abflachungsvariante:
>>> [n for lst in c2 for n in lst if n in c1set]
[13, 32, 7, 13, 28, 1, 6]
Verschachtelte Variante:
>>> [[n for n in lst if n in c1set] for lst in c2]
[[13, 32], [7, 13, 28], [1, 6]]
Der Operator & nimmt die Kreuzung zweier Sätze.
{1, 2, 3} & {2, 3, 4} Out [1]: {2, 3}
Eine pythonische Methode, um die Kreuzung von 2 Listen zu nehmen, ist:
[x for x in list1 if x in list2]
Sie sollten diesen Code abflachen (entnommen aus http://kogs-www.informatik.uni-hamburg.de/~meine/python_tricks ). Der Code wurde nicht getestet, aber ich bin mir ziemlich sicher, dass er funktioniert:
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
Nachdem Sie die Liste reduziert haben, führen Sie die Kreuzung wie üblich aus:
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))
Da intersect
definiert wurde, reicht ein grundlegendes Listenverständnis aus:
>>> c3 = [intersect(c1, i) for i in c2]
>>> c3
[[32, 13], [28, 13, 7], [1, 6]]
Verbesserung dank der Bemerkung von S. Lott und der damit verbundenen Anmerkung von TM.:
>>> c3 = [list(set(c1).intersection(i)) for i in c2]
>>> c3
[[32, 13], [28, 13, 7], [1, 6]]
Gegeben:
> 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]]
Ich finde den folgenden Code gut und vielleicht präziser, wenn Set-Operation verwendet wird:
> c3 = [list(set(f)&set(c1)) for f in c2]
Es hat:
> [[32, 13], [28, 13, 7], [1, 6]]
Wenn auftrag benötigt:
> c3 = [sorted(list(set(f)&set(c1))) for f in c2]
wir haben:
> [[13, 32], [7, 13, 28], [1, 6]]
Für einen Python-Style ist dieser übrigens auch in Ordnung:
> c3 = [ [i for i in set(f) if i in c1] for f in c2]
Ich weiß nicht, ob ich Ihre Frage zu spät beantworte. Nachdem ich Ihre Frage gelesen hatte, entwickelte ich eine Funktion intersect (), die sowohl auf der Liste als auch auf der verschachtelten Liste arbeiten kann. Ich habe Rekursion verwendet, um diese Funktion zu definieren, sie ist sehr intuitiv. Ich hoffe es ist was Sie suchen:
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
Beispiel:
>>> 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]
Betrachten Sie [1,2]
als Schnittpunkt mit [1, [2]]
? Sind es nur die Zahlen, die Sie interessieren, oder auch die Listenstruktur?
Wenn nur die Zahlen vorhanden sind, prüfen Sie, wie die Listen "abgeflacht" werden sollen, und verwenden Sie dann die set()
-Methode.
Ich suchte auch nach einem Weg, es zu tun, und schließlich endete es so:
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]
Um eine Schnittmenge zu definieren, die die Kardinalität der Elemente korrekt berücksichtigt, verwenden Sie 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(i) & set(c1)) for i in c2]
c3
[[32, 13], [28, 13, 7], [1, 6]]
Für mich ist das ein sehr eleganter und schneller Weg dazu :)
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]]
Wir können dazu Set-Methoden verwenden:
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
reduce
erstellt werden.Alles, was Sie brauchen, um Initializer - drittes Argument in der Funktion reduce
zu verwenden.
reduce(
lambda result, _list: result.append(
list(set(_list)&set(c1))
) or result,
c2,
[])
Der obige Code funktioniert sowohl für python2 als auch für python3, aber Sie müssen das Reduktionsmodul als from functools import reduce
importieren. Weitere Informationen finden Sie unter dem folgenden Link.
# 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]] ?
Hier ist eine Möglichkeit, c3
festzulegen, für die keine Sets erforderlich sind:
c3 = []
for sublist in c2:
c3.append([val for val in c1 if val in sublist])
Wenn Sie jedoch nur eine Zeile verwenden möchten, können Sie Folgendes tun:
c3 = [[val for val in c1 if val in sublist] for sublist in c2]
Es ist ein Listenverständnis innerhalb eines Listenverständnisses, das etwas ungewöhnlich ist, aber ich denke, Sie sollten nicht zu viel Mühe haben, es zu verfolgen.