2012-10-17 17 views
10

Ile można uzyskać z ciągu znaków, takiego jak , np. abcd?Podłoża ciągu znaków przy użyciu języka Python

Jak mogę uzyskać wszystkie jego podciągi:

['a', 'b', 'c', 'd', 'ab', 'bc', 'cd', 'abc', 'bcd', 'abcd'] 
+2

Zadajesz dwa różne pytania: "Ile kombinacji możesz zrobić ...?" i "Jak mogę to uzyskać jak ...". Odpowiedzi na te dwa pytania są bardzo różne. –

+0

@MarceloCantos Nie rozumiem, jak to prawda. Jedna jest tylko długością drugiej. Możesz utworzyć 'sum (1 ... n)', tzn. 'N * n (-1)/2' [substrings] (https://en.wikipedia.org/wiki/Substring) ciągu o długości' n'. –

Odpowiedz

10

Spróbuj tego:

def consecutive_groups(iterable): 
    s = tuple(iterable) 
    for size in range(1, len(s)+1): 
     for index in range(len(s)+1-size): 
      yield iterable[index:index+size] 

>>> print list(consecutive_groups('abcd')) 
['a', 'b', 'c', 'd', 'ab', 'bc', 'cd', 'abc', 'bcd', 'abcd'] 

A liczba kombinacji jest po prostu równa sumie od 1 do długości łańcucha, co jest równoważne z n * (n + 1)/2.

Przy okazji, jeśli chcesz uniknąć duplikatów, można po prostu użyć lokalnie zdefiniowane ustawienia w funkcji generatora, tak:

def consecutive_groups(iterable): 
    s = tuple(iterable) 
    seen = set() 
    for size in range(1, len(s)+1): 
     for index in range(len(s)+1-size): 
      slc = iterable[index:index+size] 
      if slc not in seen: 
       seen.add(slc) 
       yield slc 

Ten kod jest trochę bardziej nieporęczny i prawdopodobnie mógłby być zoptymalizowany pod kątem wcięcia, ale zrobi to za dowód koncepcji.

+0

Nie jestem twoim downvoter, ale to nie jest w porządku. Spróbuj 'map (partial (reduce, operator.add), powerset ('abcd'))'. – wberry

+0

Edytowane, proszę ponownie zbadać. –

+0

Generatory sprawiają, że hulk jest szczęśliwy! +1 O.o – hochl

2

To jest to, co chcesz:

In [260]: S = 'abcd' 

In [261]: list(itertools.chain.from_iterable([list(itertools.combinations(S,i)) for i in range(1,len(S))])) 
Out[261]: 
[('a',), 
('b',), 
('c',), 
('d',), 
('a', 'b'), 
('a', 'c'), 
('a', 'd'), 
('b', 'c'), 
('b', 'd'), 
('c', 'd'), 
('a', 'b', 'c'), 
('a', 'b', 'd'), 
('a', 'c', 'd'), 
('b', 'c', 'd')] 

A jeśli naprawdę chcesz je wszystkie jako ciągi znaków, można zrobić:

In [262]: combos = list(itertools.chain.from_iterable([list(itertools.combinations(S,i)) for i in range(1,len(S))])) 

In [263]: [''.join(c) for c in combos] 
Out[263]: 
['a', 
'b', 
'c', 
'd', 
'ab', 
'ac', 
'ad', 
'bc', 
'bd', 
'cd', 
'abc', 
'abd', 
'acd', 
'bcd'] 

EDIT, aby tylko dostać podciągi z S:

In [270]: list(itertools.chain.from_iterable([[S[i:i+k] for i in range(len(S)-k)] for k in range(1,len(S)+1)])) + [S] 
Out[270]: ['a', 'b', 'c', 'ab', 'bc', 'abc', 'abcd'] 
+0

Myślę, że chcesz 'itertools.combinations (S, i + 1)', aby uzyskać niezmieniony ciąg też. Również 'lista' i nawiasy kwadratowe wokół twojego wewnętrznego generatora są niepotrzebne. 'chain.from_iterable' jest całkowicie szczęśliwy biorąc generatory z generatora. – Blckknght

+0

jest pustą częścią ciągu rozwiązania? Jeśli tak, to też go brakuje. Myślę, że 'ac' również nie jest poprawnym rozwiązaniem, ponieważ pomiędzy tymi słowami brakuje' b'. – hochl

+0

dla drugiej (EDYCJA Aby uzyskać tylko podłańcuchy S :) jak znaleźć tylko podciągi o długości x? – Mathime

1

Istnieją dwa pytania .

Pierwszy How many substrings can you make out of a string like “abcd”? jest to kombinacje tak:

import itertools 
s='abcd' 
com=[list(itertools.combinations(s,x)) for x in range(1,len(s)+1)] 

print [''.join(e) for e in sum(com,[])] 

drukuje:

['a', 'b', 'c', 'd', 'ab', 'ac', 'ad', 'bc', 'bd', 'cd', 'abc', 'abd', 'acd', 'bcd', 'abcd'] 

Drugie pytanie brzmi, jak powtórzyć swój przykład (który nie jest 'Połączenie'). Można zrobić z tym kodem:

>>> [s[i:i+j] for j in range(1,len(s)+1) for i in range(len(s)-j+1)] 
['a', 'b', 'c', 'd', 'ab', 'bc', 'cd', 'abc', 'bcd', 'abcd'] 
+0

Dlaczego downstream? –

+2

Nie spadłem, ale najprawdopodobniej dlatego, że 'ac' nie jest częścią rozwiązania. – hochl

+0

@hochl: Dodałem kod do replikowania przykładu OP –

1

myślę, że to działa też i jednocześnie nie jest najbardziej wydajny, ma atrakcyjny korzystania z mniej skomplikowanych funkcji.

S = "abcd" 
substrings = [S[i:j] for i in range(len(S)) for j in range(i+1,len(S)+1)] 
substrings.sort(key=len) 

Należy jednak zauważyć, że to podejście nie usuwa identycznych podciągów, które mogą się pojawić. Na przykład, jeśli oryginalny podciąg był "abcdab", pojawiłby się dwa razy.

+0

Aby nie uwzględniać duplikatów podciągów, zmień zrozumienie listy "[...]" na zrozumienie ustawione "{...}". – mbomb007

7

Czy to wystarczy?

import itertools 
def substrings(x): 
    for i, j in itertools.combinations(xrange(len(x)+1), 2): 
     yield x[i:j] 

lub wyrażenia generatora:

(x[i:j] for i, j in itertools.combinations(xrange(len(x)+1), 2)) 

Rozwinięta wynik na swoim przykładzie wygląda następująco:

['a', 'ab', 'abc', 'abcd', 'b', 'bc', 'bcd', 'c', 'cd', 'd'] 

Aby zamówić według długości, użyj sort key=len.

Powiązane problemy