2012-10-25 21 views
5

Sprawdziłem kilka innych pytań SO (i tony google), które są "podobne", ale żaden z nich nie pasuje do mojego pytania.Python unikalne tworzenie ciągów

Próbuję utworzyć stałą długość, unikatowy ciąg tekstowy, zawierający tylko znaki w określonym przeze mnie ciągu. Na przykład. składa się z wielkich i małych liter a-zA-Z. (W tym przykładzie należy używać tylko A, B i C, małymi literami)

coś w tym (kod łamany poniżej)

def next(index, validCharacters = 'abc'): 
    return uniqueShortAsPossibleString 

Argument wskaźnik byłby indeksem (liczba całkowita), które odnoszą się do tekstu ciąg, na przykład:

next(1) == 'a' 
next(2) == 'b' 
next(3) == 'c' 

next(4) == 'aa' 
next(5) == 'ab' 
next(6) == 'ac' 

next(7) == 'ba' 
next(8) == 'bb' 
next(9) == 'bc' 

next(10) == 'ca' 
next(11) == 'cb' 
next(12) == 'cc' 

I tak dalej. Łańcuch:

  1. Musi być unikalny, będę go używał jako identyfikator, a to może być tylko a-zA-Z zwęgla
  2. tak krótki, jak to możliwe, przy czym indeksy dolne numery najkrótszy (patrz Powyższe przykłady)
  3. zawierać tylko znaki określone w podanych argumencie validCharacters

Podsumowując, jak mógłbym napisać następną funkcję(), aby odnosić się wartość indeksu całkowitą do unikalnego krótkiego łańcucha ze znaków określonych ?

P.S. Jestem nowy w SO, ta strona pomogła mi przez lata, a ja nigdy nie założyłem konta ani nie zadałem pytania (do tej pory), mam nadzieję, że wykonałem dobrą robotę wyjaśniając, czym jestem próbując to osiągnąć.

+0

Uważaj na powtarzające się odpowiedzi. Chociaż mogą one działać, musisz zapisać stan, jeśli chcesz powrócić tam, gdzie skończyłeś, bez przeliczania wszystkich poprzednich wartości. – agf

Odpowiedz

1

Starasz przekonwertować liczbę do liczby w innej bazie, ale przy użyciu dowolnych znaków dla cyfr tej podstawy.

import string 
chars = string.lowercase + string.uppercase 

def identifier(x, chars): 
    output = [] 
    base = len(chars) 
    while x: 
     output.append(chars[x % base]) 
     x /= base 
    return ''.join(reversed(output)) 

print identifier(1, chars) 

ta pozwala przeskoczyć do dowolnego miejsca, liczysz więc identyfikatory są zupełnie wyjątkowe i jest łatwy w użyciu dowolnego zestawu znaków o dowolnej długości (dwóch lub więcej), a niższe numery dać krótszy identyfikatory.

+0

"Odwrócony" nie jest tu konieczny, ponieważ martwisz się tylko długością, a nie kolejnością. – agf

+0

Uwaga: 'identyfikator (123456789, znaki)' zwraca 'þƒžå' –

+0

Zaakceptowany (i + 1'd?) To jest dokładnie to, czego potrzebowałem i doceniam implementację. Wiedziałem, że to coś takiego, po prostu nie mogłem tego położyć! – powerpup118

1

itertools zawsze może dać Ci ukrywane iteratory jedną Wkład:

from itertools import combinations_with_replacement, chain 

chars = 'abc' 
a = chain(*(combinations_with_replacement(chars, i) for i in range(1, len(chars) + 1))) 

Zasadniczo ten kod tworzy iterator, który łączy wszystkie kombinacje chars długościach 1, 2, ... len(chars).

Wyjście for x in a: print x jest:

('a',) 
('b',) 
('c',) 
('a', 'b') 
('a', 'c') 
('b', 'a') 
('b', 'c') 
('c', 'a') 
('c', 'b') 
('a', 'b', 'c') 
('a', 'c', 'b') 
('b', 'a', 'c') 
('b', 'c', 'a') 
('c', 'a', 'b') 
('c', 'b', 'a') 
+0

+1 za sprawienie, że poczuję się jak noob. Rozwiązałem ten problem kilka miesięcy temu, była to cholerna misja :) – Sheena

1

naprawdę nie można „współpracownik” indeks z irytujące, ale po to generator, który przyniesie i zapewnić wyjście Prosisz o:

from itertools import combinations_with_replacement 

def uniquenames(chars): 
    for i in range(1, len(chars)): 
     for j in combinations_with_replacement(chars, i): 
      yield ''.join(j) 

print list(uniquenames('abc')) 
# ['a', 'b', 'c', 'aa', 'ab', 'ac', 'bb', 'bc', 'cc'] 
+0

+1 za czytelny kod – Blender

+0

@Blender Dzięki, po prostu zdałem sobie sprawę, że brakuje niektórych ... muszę naprawić to –

3

To, co próbujesz zrobić, to wpisać parametr funkcji w innej bazie.

Załóżmy validCharacters zawiera k znaki: to zadanie funkcji next będzie przekształcenie parametru p do bazy k za pomocą znaków w validCharacters.

w przykładzie, można napisać numery w podstawy 3, a następnie powiązać każdą cyfrę z jednej litery:

next(1) -> 1 -> 'a' 
next(2) -> 2 -> 'b' 

next(4) -> 11 -> 'aa' 
next(7) -> 21 -> 'ba' 

i tak dalej.

Za pomocą tej metody można zadzwonić pod numer next(x) bez znajomości lub obliczenia wartości next(x-i), której nie można wykonać metodami iteracyjnymi.

+0

Wdrożenie w mojej odpowiedzi. – agf

+0

+1 za pomysł, potrzebowałem czegoś w rodzaju implementacji podstawowej lub kodu psuedo, aby to zrozumieć. – powerpup118

0

Wygląda na to, że próbujesz wyliczyć wszystkie łańcuchy wygenerowane przez język {'a', 'b', 'c'}. Można to zrobić za pomocą finite state automata (choć nie chcesz tego robić). Jednym prostym sposobem wyliczenia przez język jest rozpoczęcie od listy i dołączenie wszystkich łańcuchów o długości 1 w kolejności (a więc a następnie b, a następnie c). Następnie dopisz każdą literę alfabetu do każdego ciągu o długości n-1. Utrzyma to porządek, o ile dołączysz wszystkie litery alfabetu do danego ciągu znaków, zanim przejdziesz do następnej sekwencji leksykograficznej.

+1

Ten problem jest znacznie prostszy. – agf

1

Z tego co rozumiem, nie powinniśmy określać maksymalnej długości ciągów wyjściowych. Więc range nie wystarczy:

>>> from itertools import combinations_with_replacement, count 
>>> def u(chars): 
...  for i in count(1): 
...   for k in combinations_with_replacement(chars, i): 
...    yield "".join(k) 
... 
>>> g = u("abc") 
>>> next(g) 
'a' 
>>> next(g) 
'b' 
>>> next(g) 
'c' 
>>> next(g) 
'aa' 
>>> next(g) 
'ab' 
>>> next(g) 
'ac' 
>>> next(g) 
'bb' 
>>> next(g) 
'bc' 
+0

+1 dla 'count'. To jest poprawna odpowiedź. – Blender

+0

@Blender Nie sądzę, że w tym przypadku odpowiedzi iteracyjne rozwiązują właściwy problem. – agf

Powiązane problemy