Überprüfung wie viele items in set

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
schneitzmaster
User
Beiträge: 94
Registriert: Freitag 26. Oktober 2012, 15:35
Wohnort: Hamburg

Hallo Leute,

ich habe ein "Haupt"-liste mit integern und eine verschachtelte liste ebenfals mit integern. Nun möchte ich die elemente der verschachtelten Liste heraus ziehen, die genau 3 elemente mit der "Haupt"-liste gemeinsam haben. Je nach dem welche position die gemeinsamen Elemente der haben soll noch in 4 Fälle unterschieden werden.
Momentan läuft das über eine for-schleife in kombination mit einer list-comprehension über:

Code: Alles auswählen

# INPUT
hauptliste= [1,2,3,4,5,6,7,8,9]
sub_liste = [[1,2,10,4],
             [5,20,10,9],
             [8,30,5,7]]
# INPUT-ENDE
hauptliste = set(hauptliste)
rslt = []
for i,sub_liste_i in enumerate(sub_liste):
    tmp = [item in hauptliste for item in sub_liste_i]
    if sum(tmp)==3:
        if   tmp[0] and tmp[1] and tmp[2]: # CASE 1
            rslt.append([i,1])
        elif tmp[0] and tmp[1] and tmp[3]: # CASE 2
            rslt.append([i,2])
        elif tmp[1] and tmp[2] and tmp[3]: # CASE 3
            rslt.append([i,3])
        else:
            rslt.append([i,4]) # CASE 4

print rslt
Geht das noch schneller und eleganter, da in der Realität die "Haupt"liste sehr groß ist. Gibt es da vllt. etwas in numpy? Ich bin leider noch nicht fündig geworden.
Grüße
Zuletzt geändert von schneitzmaster am Dienstag 8. September 2015, 08:49, insgesamt 2-mal geändert.
Benutzeravatar
MagBen
User
Beiträge: 799
Registriert: Freitag 6. Juni 2014, 05:56
Wohnort: Bremen
Kontaktdaten:

Mit Numpy geht das auch mit Millionen von Werten performant.

Code: Alles auswählen

import numpy as np

hauptliste= np.array([1,2,3,4,5,6,7,8,9])
sub_liste = np.array([[1,2,10,4],
                      [5,20,10,9],
                      [8,30,5,7]])

position = np.searchsorted(hauptliste, sub_liste)
position[position==hauptliste.size] = 0
uebereinstimmung = (hauptliste[position]==sub_liste)
anzahl = np.array([np.count_nonzero(zeile) for zeile in uebereinstimmung])
ergebnis = np.arange(anzahl.size)[anzahl==3] 
print ergebnis # [0 2]
print sub_liste[uebereinstimmung[ergebnis]].reshape(-1,3)
# [[ 1  2  4]
#  [ 5 10  9]] 
Damit der Code funktioniert, müssen die Werte der Hauptliste sortiert sein und alle Zeilen der sub_liste müssen die gleiche Anzahl an Elementen haben. Wegen dem Trick in Zeile 9 muss die Hauptliste mindestens 2 Elemente enthalten. Nur Zeile 11 enthält eine Schleife in Python, alle anderen Schleifen laufen extrem schnell innerhalb von Numpy. Die runden Klammern in Zeile 10 sind nicht notwendig, macht die Sache aber klarer.
a fool with a tool is still a fool, www.magben.de, YouTube
schneitzmaster
User
Beiträge: 94
Registriert: Freitag 26. Oktober 2012, 15:35
Wohnort: Hamburg

super vielen dank!
genau nach so etwas habe ich gesucht.
BlackJack

@schneitzmaster: `set` kommt zwar im Betreff vor und sogar in einer Zeile im Quelltext, dort führt es aber zu einem `NameError` weil `liste` nicht definiert ist. Und wenn es in der Zeile definiert würde: Der Name wird sonst nirgends verwendet.

Die Namen sind insgesamt nicht so toll. `rslt`? Sind auf Deiner Tastatur keine Vokale, oder muss man extra bezahlen wenn man die benutzt? `sub_liste` enthält Listen (Mehrzahl), sollte also `sub_listen` heissen. Und schön bräuche man für eine dieser Unterlisten kein komisches `_i` mehr an den Namen `sub_liste` hängen.

Alternative:

Code: Alles auswählen

def function(main_list, sub_lists):
    main_list = set(main_list)
    result = list()
    for i, sub_list in enumerate(sub_lists):
        positions = [j for j, x in enumerate(sub_list) if x in main_list]
        # 
        # Alternative wenn `sub_list` deutlich länger als im Beispiel sein
        # kann, dann könnte man etwas gewinnen in dem man die Suche nach
        # den Positionen auf das Minimum begrenzt das nötig ist um die
        # nachfolgende Entscheidung zu treffen:
        # 
        # positions = list(
        #     islice((j for j, x in enumerate(sub_list) if x in main_list), 4)
        # )
        # 
        if len(positions) == 3:
            for k, case in enumerate([[0, 1, 2], [0, 1, 3], [1, 2, 3]], 1):
                if positions == case:
                    result.append([i, k])
                    break
            else:
                result.append([i, k + 1])

    return result
schneitzmaster
User
Beiträge: 94
Registriert: Freitag 26. Oktober 2012, 15:35
Wohnort: Hamburg

Hallo BlackJack,

danke für die Hinweise. Ich hatte einen Tipfehler und den jetzt im Eingangspost behoben. Es muss natürlich

Code: Alles auswählen

hauptliste = set(hauptliste)
heißen.
Desweiteren danke ich auch für die Namensvorschläge. Ich tu mich immer schwer treffende Variablennamen zu finden. Die werden meist sehr lang. Aus diesem Grund habe ich auch nicht result sonder die Kurzform rslt benutzt. Die entsprechenden Befehle / Zeilen in meinem Code werden halt schnell lang und um noch im 80-Zeichen-pro-Zeile-Limit zu bleiben habe ich mir angewöhnt soweit es geht mit abkürzungen zu arbeiten. Klar mit 'sub_listen' stimme ich dir auch voll zu. Allerdings finde ich ist es leicher im Code 'sub_liste_i' zu erkennen als zwischen 'sub_listen' und 'sub_liste' zu differenzieren.
schneitzmaster
User
Beiträge: 94
Registriert: Freitag 26. Oktober 2012, 15:35
Wohnort: Hamburg

@BlackJack:
bei deinem ersten Post kann ich die For-Schleife noch mit

Code: Alles auswählen

anzahl = np.sum(uebereinstimmung,axis=1)
umgehen
Antworten