2009-09-28 16 views
5

Cześć, kodery i kodery!Ocena na dwie lub więcej list

Natknąłem się na prosty problem z pozornie łatwym rozwiązaniem. Ale będąc neofitą w Pythonie, czuję, że jest gdzieś lepsze podejście.

Powiedz, że masz listę mieszanych ciągów znaków. W worku są dwa podstawowe typy strun - te z "=" w nich (a = ziemniak) i te bez (Lady Jane). To, czego potrzebujesz, to posortować je na dwie listy.

Oczywistym rozwiązaniem jest:

for arg in arguments: 
    if '=' in arg: 
     equal.append(arg) 
    else: 
     plain.append(arg) 

Czy istnieje inny, bardziej elegancki sposób do niego? Coś jak:

equal = [arg for arg in arguments if '=' in arg] 

, ale podzielić na wiele list?

A co, jeśli masz więcej niż jeden typ danych?

+3

Myślę, że twoje oczywiste podejście jest doskonale dobre i dużo czytelniejsze niż wiele odpowiedzi zasugerowałem do tej pory! –

+0

Rzeczywiście uważam, że rozumienie list jest jedną z najbardziej eleganckich cech Pythona, którego nieustannie pragnę podczas pisania C++! 2 z nich są o wiele ładniejsze niż jakakolwiek z odpowiedzi. – Steg

Odpowiedz

4

Spróbuj

for arg in arguments: 
    lst = equal if '=' in arg else plain 
    lst.append(arg) 

lub (święty brzydki)

for arg in arguments: 
    (equal if '=' in arg else plain).append(arg) 

Trzecia opcja: Tworzenie klasy, która oferuje append() i która sortuje na kilku listach.

+0

Znajduję bardziej czytelny formularz 'list = ('=' w arg) i równy lub zwykły'. – giorgian

+0

jesteś w cieniu wbudowany – SilentGhost

+0

Myślę, że "a jeśli cond else b" jest bardzo czytelny po angielsku; Po prostu nie lubię wkładać zbyt wiele w jedną linię. –

4

itertools.groupby() Można użyć do tego:

import itertools 
f = lambda x: '=' in x 
groups = itertools.groupby(sorted(data, key=f), key=f) 
for k, g in groups: 
    print k, list(g) 
+3

Myślałem, że poprosił o elegancki – Steg

+0

Sortowanie czyni go nlog (n), podczas gdy istnieje prostsze rozwiązanie O (n). –

1

Innym podejściem jest użycie funkcji filter, choć nie jest to najbardziej efektywne rozwiązanie.
Przykład:

>>> l = ['a=s','aa','bb','=', 'a+b'] 
>>> l2 = filter(lambda s: '=' in s, l) 
>>> l3 = filter(lambda s: '+' in s, l) 
>>> l2 
['a=s', '='] 
>>> l3 
['a+b'] 
2
def which_list(s): 
    if "=" in s: 
     return 1 
    return 0 

lists = [[], []] 

for arg in arguments: 
    lists[which_list(arg)].append(arg) 

plain, equal = lists 

Jeśli masz więcej rodzajów danych, jeśli dodać klauzulę which_list i zainicjować lists bardziej pustych list.

+0

która_lista może być dużo prostsza - zobacz moją odpowiedź. W przeciwnym razie nasze odpowiedzi są dość bliskie. – PaulMcG

+0

Rzeczywiście, może tak być, ale OP zapytał o przypadek więcej niż dwóch możliwości, którymi chciałem się zająć w pierwotnym projekcie. –

+0

W takim przypadku myślę, że słownik list będzie bardziej przejrzysty. Indeksy listy są bez znaczenia. –

3

Chciałbym po prostu przejść do dwóch list ze zrozumieniem. Chociaż powoduje to pewne obciążenie (dwie pętle na liście), jest to bardziej Python, niż użycie klawisza for. Jest to również (moim zdaniem) znacznie bardziej czytelne niż używanie wszelkiego rodzaju naprawdę fajnych sztuczek, ale o tym mniej osób wie.

1

Połączyłem to i zobaczyłem, że Ned Batchelder był już na tym samym halsie. Jednak wybrałem spakowanie metody podziału zamiast selektora list i użycie niejawnych wartości 0/1 dla False i True.

def split_on_condition(source, condition): 
    ret = [],[] 
    for s in source: 
     ret[condition(s)].append(s) 
    return ret 

src = "z=1;q=2;lady jane;y=a;lucy in the sky".split(';') 

plain,equal = split_on_condition(src, lambda s:'=' in s) 
1

Twoje podejście jest najlepsze. Do sortowania tylko na dwie listy nie można uzyskać wyraźniejszego niż to. Jeśli chcesz, aby był jednolinijkowy, zamknij go w funkcji:

def classify(arguments): 
    equal, plain = [], [] 
    for arg in arguments: 
     if '=' in arg: 
      equal.append(arg) 
     else: 
      plain.append(arg) 
    return equal, plain 


equal, plain = classify(lst) 
2

Chciałbym pójść na podejście Edana, np.

equal = [arg for arg in arguments if '=' in arg] 
plain = [arg for arg in arguments if '=' not in arg] 
2

Czytałem gdzieś tutaj, że może być zainteresowany w roztworze, który będzie pracować dla więcej niż dwóch identyfikatorów (znak równości i przestrzeni).

Poniżej rozwiązanie wymaga tylko zaktualizować zestaw uniques z coś, co chciałbyś, aby dopasować wyniki są umieszczane w słowniku list z identyfikatorem jako klucz.

uniques = set('= ') 
matches = dict((key, []) for key in uniques) 

for arg in args: 
    key = set(arg) & uniques 
    try: 
     matches[key.pop()].append(arg) 
    except KeyError: 
     # code to handle where arg does not contain = or ' '. 

Teraz powyższy kod zakłada, że ​​będzie tylko jeden mecz dla swojego identyfikatora w arg. To znaczy, że nie masz arg, który wygląda tak: 'John= equalspace'. Będziesz musiał również pomyśleć o tym, jak chcesz traktować przypadki, które nie pasują do niczego w zestawie (KeyError).

Powiązane problemy