2016-07-08 6 views
2

Ich habe eine Liste von 4-Tupeln. Ich möchte überprüfen, ob es mindestens ein Tupel mit seinem dritten Element hat, das gleich 'JJ' ist und mindestens ein Tupel mit seinem vierten Element gleich 'nsubj' ist. Diese müssen jedoch nicht notwendigerweise das gleiche Tupel sein.Mehrere nicht-konjunktive Bedingungen für Listenverständnis

So wie etwas zu tun -

if (any([tup for tup in parse_tree[i] if (tup[2] == 'JJ' and tup[3] == 'nsubj')])): 

ist falsch.

Stattdessen, wenn Sie tun

if (any([tup for tup in parse_tree[i] if (tup[2] == 'JJ' or tup[3] == 'nsubj')])): 

Sie werden Listen erhalten, die mindestens eine Bedingung erfüllen, aber nicht beides.

Der einzige Weg, ich denke, könnte dies zu lösen war von this- tun

if any([tup for tup in parse_tree[i] if tup[2] == 'JJ']) and any([tup for tup in parse_tree[i] if tup[3] == 'nsubj']): 

Gibt es eine Möglichkeit, dies mit nur einer Liste zu tun?

+1

Während es Ihr Problem nicht lösen wird, reduziert die Verwendung von Generatorausdrücken die Laufzeit.Lege die '[]' von deiner letzten Anweisung ab - 'any' stoppt, sobald ein Element' True' ist, aber die '[]' erzwingt, dass alle Elemente im Moment erzeugt werden. – MisterMiyagi

+1

Ein Listenverstehen mit Status zu haben ist eine schlechte Idee. Der einfachste Weg, dies zu tun, ist eine einfache Schleife und Flags für jedes Ding, das Sie suchen. – jonrsharpe

+0

@jonrsharpe Ist das nicht unpythonisch? –

Antwort

1

Sie könnten Gruppe alle 3. und 4. Elemente aus den Tupeln in der Liste in neue Tupel in einer anderen Liste zip und anschließend von diesen neuen Tupel direkt für die Elemente überprüfen:

# say lst is your original list 

new_lst = zip(*lst) 
if 'JJ' in new_lst[2] and 'nsubj' in new_lst[3]: 
    # your code 

Natürlich, wenn die Schaffung eine neue Liste von Ihrer ursprünglichen Liste ist erlaubt

1

Ich kann nicht eine rein boolean plus any/all Lösung zu diesem denken. Ohne Primitive können Sie dies mit einem benutzerdefinierten Vergleichsobjekt lösen, das den Status behält.

class MultiComp(object): 
    def __init__(self, *conditions): 
     self._conditions = conditions 
     self._results = [False] * len(conditions) 

    def __bool__(self): 
     return all(self._results) 

    __nonzero__ = __bool__ 

    def digest(self, elem): 
     for idx, condition in enumerate(self._conditions): 
      if not self._results[idx] and condition(elem): 
       self._results[idx] = True 
     return self 

comp = MultiComp(lambda tup: tup[2] == 'JJ', lambda tup: tup[3] == 'nsubj') 
any(tup for tup in ttuple if bool(comp.digest(tup))) 

Beachten Sie, dass dies mehr als zehnmal langsamer als richtig beide Bedingungen Auswertung ist.

Vergleich Klasse:

In [215]: %%timeit 
    .....: comp = MultiComp(lambda tup: tup[2] == 'JJ', lambda tup: tup[3] == 'nsubj') 
    .....: any(tup for tup in ttuple if bool(comp.digest(tup))) 
    .....: 
10000 loops, best of 3: 30.6 µs per loop 

ordnungsgemäß mit Generatoren:

In [216]: %%timeit 
    .....: any(tup[2] == 'JJ' for tup in ttuple) and any(tup[3] == 'nsubj' for tup in ttuple) 
    .....: 
100000 loops, best of 3: 4.26 µs per loop 
0

Vielleicht können Sie mit so etwas wie Generatoren tun (was effizienter ist) anstelle von Listen per se.

Gibt es einen bestimmten Grund, warum Sie es mit nur einer Liste machen müssen?

if any(True for tuple_list in list_of_tuple_lists if any(True for t in tuple_list if t[2]=='JJ') and any(True for t in tuple_list if t[3] == 'nsubj')) 

Und Ihre Benennung entsprechen:

if any(True for tuple_list in parse_tree[i] if any(True for t in tuple_list if t[2]=='JJ') and any(True for t in tuple_list if t[3] == 'nsubj')) 

Dieser Code für alle Fälle funktioniert. Einfacher Test:

import random 
import time 

none = [(1,2,3,4),(1,2,3,4),(1,2,3,4),(1,2,3,4)] # none of the conditions 
first = [(1,2,3,4),(1,2,'JJ',4),(1,2,3,4),(1,2,3,4)]# only first of the conditions 
second = [(1,2,3,4),(1,2,'test',4),(1,2,4,'nsubj'),(1,2,3,4)]# only second of the conditions 
both = [(1,2,'JJ',4),(1,2,'test',4),(1,2,3,'nsubj'),(1,2,3,4)]# both of the conditions in different tuples 
same = [(1,2,'JJ','nsubj'),(1,2,'test',4),(1,2,2,4),(1,2,3,4)]# both of the conditions in same tuple 
possible_tuples=[none,first,second,both,same] 


def our_check(list_of_tuple_lists): 
    if any(True for tuple_list in list_of_tuple_lists if any(True for t in tuple_list if t[2]=='JJ') and any(True for t in tuple_list if t[3] == 'nsubj')): 
     return True 
    else: 
     return False 


def our_check_w_lists(list_of_tuple_lists): 
    if any([True for tuple_list in list_of_tuple_lists 
      if any([True for t in tuple_list if t[2]=='JJ']) and any([True for t in tuple_list if t[3] == 'nsubj'])]): 
     return True 
    else: 
     return False 


def third_snippet(list_of_tuple_lists): 
    if any([tup for tup in list_of_tuple_lists if tup[2] == 'JJ']) and any([tup for tup in list_of_tuple_lists if tup[3] == 'nsubj']): 
     return True 
    else: 
     return False 

def test(func): 
    test_cases = [] 
    for n in range(100000): 
     test_list=[] 
     for i in range(10): 
      test_list.append(random.choice(possible_tuples)) 
     expected = False 
     if both in test_list or same in test_list: 
      expected = True 

     test_case = expected, test_list 
     test_cases.append(test_case) 
    start = time.clock() 
    for expected, case_list in test_cases: 
     if expected != func(case_list): 
      print('%s, Fail for: %s'%(func,case_list)) 
      return False 
    end = time.clock() 
    print('function:%s, %f'%(func, end-start)) 

test(our_check) 
test(our_check_w_lists) 
test(third_snippet) 

Diese Testergebnisse zeigt Unterschied Ausführungszeit zwischen Generatoren und Liste Verständnis mit für nur 10-Tupel lange Liste.

function:<function our_check at 0x00000000028CE7B8>, 0.378369 
function:<function our_check_w_lists at 0x00000000031472F0>, 1.270924 
<function third_snippet at 0x00000000031E0840>, Fail for: [[... 
+0

Danke für die Antwort, aber macht das nicht genau das, was ich mache, sondern stelle es in eine Funktion? –

+0

@NikhilPrabhu Ich habe gerade die Funktion zum Testen eingefügt. Sie können das kurze Snippet oben verwenden, in dem list_of_tuple_lists parse_tree [i] lauten würde, um Ihren Code zu finden. Es macht nicht dasselbe, da es nur Generatoren verwendet und keine Liste erstellt. Any() -Anweisung mit Generator als Argument wird aufhören, sobald es True erhält. Wenn Sie [] Listenverständnis verwenden, wird die vollständige Liste unabhängig davon erzeugt, wo und wann die Bedingungen erfüllt sind. Außerdem scheitert Ihr dritter Schnipsel in meinem Test. –

+0

@NikhilPrabhu Ich habe meine Antwort aktualisiert, um Unterschiede in der Leistung zwischen Generatoren und Listenverständnis zu zeigen. –