2012-05-02 14 views
8

Oto przykładowy formularz, postaram się wyjaśnić to później w słowach. Mam listę z rozbijając ciąg ...Jak przetworzyć ciąg na warstwę podlisty

powiedzenia

[a, a, a, b, a, a, b, a, c, a, b, a, a, c, a, c, a] 

gdzie b to kryteria 1 i C jest kryterium 2

chcę podzielić go na liście, jak poniżej:

[a, a, a, [b, a, a, [b, a, c], a, [b, a, a, c], a, c], a] 

Więc chcę przetworzyć ciąg taki, że gdy idę przez niego, jeśli element pasuje do kryteriów 1, otworzyć nową listę, czy pozycja odpowiada kryteriom 2, zamknij lista a nd zwraca jeden poziom wyżej.

Próbowałem zrobić coś takiego, ale to nie działa bardzo dobrze.

def sublist(self, l): 
    for line in list: 
    if not b: 
    self.data.append(line) 
    else: 
    sublist(l[line:])  #<----- not sure how to recurse it. 

Widziałem łamanie listy do listy równej wielkości zanim na stackoverflow, ale nie jedno włamanie do podmenu za pomocą zestawu kryteriów.

Jestem dość nowy dla Pythona, więc nie jestem zbyt zaznajomiony z strukturami danych i narzędziami iteratora.

Odpowiedz

10

tutaj przejść:

lst = "aaabaabacabaacaca" 

def go(it): 
    for x in it: 
     if x == 'b': 
      yield [x] + list(go(it)) 
     else: 
      yield x 
      if x == 'c': 
       break 


print list(go(iter(lst))) 
+2

Nice. Generatory zdecydowanie upraszczają strukturę rekursywną. – Marcin

+0

(+1) Ładne rozwiązanie! – NPE

+0

Należy zauważyć, że obsługuje to "niedomiar", kończąc dane wyjściowe. To może nie być to, co jest pożądane. – Marcin

1
addlist = [] 
alllists = [] 
for item in mylist: 
    if item == b: 
     newlist = [item] 
     addlist.append(newlist) 
     alllists.append(addlist) 
     addlist = newlist 
    elif item == c: 
     addlist.append(item) 
     addlist = alllists.pop() 
    else: 
     addlist.append(item) 

Powyższy będzie działać tak długo, jak b i c ograniczniki są zrównoważone; w szczególności, jeśli masz nadmiar c s, będziesz miał niedopełnienie stosu.

Podczas gdy ja często lubię rekursywne rozwiązania, ma to tę zaletę, że czyni stos wyraźnym, co w tym przypadku, moim zdaniem, prowadzi do łatwiejszego grokowania kodu.

0

Następujące będzie to zrobić:

a, b, c = 1, 2, 3 

def sublist(l): 
    ret = [] 
    while l: 
    val = l.pop(0) 
    if val == b: 
     ret.append([val] + sublist(l)) 
    else: 
     ret.append(val) 
     if val == c: break 
    return ret 

l = [a, a, a, b, a, a, b, a, c, a, b, a, a, c, a, c, a] 
print l 
print sublist(l) 

pamiętać, że ta ma efekt uboczny modyfikacji l. Przejście do kopii jest banalnie proste.

1

ze stosu:

def parseList(inList): 
    stack = [[]] 
    for element in inList: 
     if element == 'b': 
      stack.append([element]) 
      stack[-2].append(stack[-1]) 
     elif element == 'c': 
      stack.pop().append(element) 
     else: 
      stack[-1].append(element) 
    return stack[0] 

to pęknie, jeśli istnieje więcej 'c, niż' B

+0

To rozwiązanie nie działa, na przykład w pytaniu OP tworzy indeks indeksu IndexError: poza zasięgiem, –

+0

dzięki Oscar, nie przetestowałem go przed opublikowaniem. naprawiony. – sobel

0

W prawdziwym stylu rekursji można wykonać następujące:

x = yourlist 
i = 0 
def lets_parse(): 
    global i 
    fnlist = [] 
    while i < len(x) 
     if x[i] == 'c': 
      fnlist.append(x[i]) 
      i += 1 
     return fnlist 
     elif x[i] == 'b': 
      i += 1 
      f = lets_parse() 
      f.insert(0, 'b') 
      fnlist.append(f) 
     else: 
      fnlist.append(x[i]) 
      i += 1 
return fnlist 

print lets_parse() 

Zwróć uwagę na użycie globali. Wielu krytyków może sprzeciwić się temu jako zły styl kodowania.

+0

Rzeczywiście, to zły styl kodowania. W "prawdziwej rekursji" nie trzeba używać zmiennych globalnych, wynik jest przekazywany jako parametry i zwracane wartości funkcji rekursywnej. –

0
import ast  
mylist = '[a, a, a, b, a, a, b, a, c, a, b, a, a, c, a, c, a]' 
mylist = mylist.replace('a','"a"') 
mylist = mylist.replace('b','["b"') 
mylist = mylist.replace('c','"c"]') 
print ast.literal_eval(mylist) 
#Output: 
['a', 'a', 'a', ['b', 'a', 'a', ['b', 'a', 'c'], 'a', ['b', 'a', 'a', 'c'], 'a', 'c'], 'a'] 
1

Są bardzo ładne odpowiedzi na to pytanie, szczególnie podobała mi thg435 za rekurencyjną rozwiązanie przy użyciu generatorów i iteracyjnego rozwiązania Marcin która dodaje elementy do list referencyjnych.

Znalazłem także niepokojące, że niektóre rozwiązania modyfikują listę wejściową lub używają stanu globalnego. To, IMHO, jest sprzeczne z prawdziwym duchem rekurencyjnego rozwiązania.Poniżej znajduje się moja próba czysto funkcjonalnego, rekurencyjnego rozwiązania w Pythonie - przyznane, istnieje wiele bardziej idiomatycznych i skutecznych sposobów rozwiązania tego problemu, ale chciałem napisać odpowiedź tak, jak napisałem to w czysto funkcjonalnym języku programowania:

# lst: the list to be processed 
# acc: accumulated result 
# stk: temporary stack 
def process(lst, acc, stk): 
    if not lst: 
     return acc 
    elif lst[0] == 'b': 
     return process(lst[1:], [lst[0]], [acc] + stk) 
    elif lst[0] == 'c': 
     return process(lst[1:], stk[0] + [acc + [lst[0]]], stk[1:]) 
    else: 
     return process(lst[1:], acc + [lst[0]], stk) 

lst = ['a', 'a', 'a', 'b', 'a', 'a', 'b', 'a', 'c', 'a', 'b', 'a', 'a', 'c', 'a', 'c', 'a'] 
process(lst, [], []) 
> ['a', 'a', 'a', ['b', 'a', 'a', ['b', 'a', 'c'], 'a', ['b', 'a', 'a', 'c'], 'a', 'c'], 'a'] 

niektóre szczegóły zauważyć:

  • nie używać zmiennych lokalnych i zmiennych globalnych, tylko parametry funkcji do śledzenia stanu
  • nie używać operatorów przypisania
  • Bez iteratorów i luzu ps są używane do przechodzenia przez listę wejściową, tylko rekursja
  • To rekurencyjne rozwiązanie, chociaż nie ma to znaczenia w Pythonie
  • Używane są tylko wyrażenia; Operacje takie jak append lub extend (które zwracają None) unika
  • Brak listy są coraz zmodyfikowane (włączając listy wejściowego), natomiast nowe listy są tworzone w miarę potrzeb (za pomocą plastrów tablicy do tego)
  • Jest to raczej krótka i elegancki rozwiązanie, ale to może być subiektywna opinia :)
Powiązane problemy