2013-01-14 15 views
9

Si dispone di un elenco di numeri e si desidera filtrare quei numeri che contengono cifre univoche, vale a dire ogni cifra può verificarsi solo una volta nel numero.Come filtrare i numeri che contengono cifre univoche?

Esempi positivi:

  • 58293,6
  • esempi 0,1246

negative:

  • 9585 (5 si verifica due volte)
  • 58293.666 (6 si verifica tre volte)
  • 0,12461 (1 si verifica due volte)

Come hai fatto? La mia idea è di convertire ogni numero in una stringa e quindi verificare se la dimensione del set ricavata dai caratteri della stringa è uguale alla lunghezza della stringa. Qualcosa del genere:

def uniques(numbers): 
    for number in numbers: 
     str_number = str(number) 
     if len(set(str_number)) == len(str_number): 
      yield number 

for i in uniques(xrange(1000, 1050)): 
    print i 

1023 
1024 
1025 
1026 
1027 
1028 
1029 
1032 
1034 
1035 
1036 
1037 
1038 
1039 
1042 
1043 
1045 
1046 
1047 
1048 
1049 

C'è un modo per farlo senza prima convertire gli interi in stringhe?

+2

Non riconvertirlo. Prendi un'altra variabile per la versione con stringhe del numero. – Matthias

+0

Specialmente se il tuo input contiene 'float's ... –

+3

A parte ciò, penso che il tuo approccio sia semplice e facile da capire. Ci andrei. –

risposta

8

C'è un modo per farlo senza convertire i numeri interi in stringhe prima e poi convertirli indietro?

Sì, è possibile utilizzare divmod per trovare la base di cifre 10, ma questo non è più veloce rispetto al metodo che avete inviato:

def uniques2(numbers): 
    for number in numbers: 
     seen = set() 
     quotient = number 
     while quotient > 10: 
      quotient, remainder = divmod(quotient, 10) 
      if remainder in seen: 
       break 
      else: 
       seen.add(remainder) 
     else: 
      yield number 
+0

+1. Molto bella. Questo è esattamente quello che stavo cercando. Sulla mia macchina, il tuo metodo è anche leggermente più veloce della mia soluzione. Molto bene. :) – pemistahl

5

Prova:

def predicate(n): 
    s = repr(n) 
    return len(s) == len(set(s)) 
filtered_numbers = [ n for n in numbers if predicate(n) ] 

o, se si preferisce la funzione di filtro:

filtered_numbers = filter(predicate, numbers) 

o:

filtered_numbers = filter(lambda n: len(repr(n)) == len(set(repr(n))), numbers) 
+1

+1 per 'lambda' :) –

+1

Quindi usando' repr' invece di 'str', è la stessa cosa che dice in modo diverso – Abhijit

+1

@Abhijit, c'è una piccola differenza tra repr (1.0/7.0) e str (1.0 /7.0), per esempio. –

3

Se si desidera una soluzione regex-based, si consideri la seguente espressione regolare :

(?![\d.]*([\d.])[\d.]*\1)^[\d.]+$ 

Cioè, corrisponde una sequenza di cifre e periodi se non ci sono cifre duplicate e non esiste un punto decimale duplicato.

Update (grazie @frb): il modo corretto di scrivere questo in Python è

re.match(r"(?![\d.]*([\d.])[\d.]*\1)^[\d.]+$",str_number).group(0) 
+0

@frb IIUC, la sorgente è un numero _converted_ to string, quindi '1.1.1' non può verificarsi. Ad ogni modo, '1.1.1' dovrebbe _non_ match. Se vuoi lamentarti, lamentati di '1.2.3' –

+0

@frb' 1.1.1' non corrisponde: link: http://regexpal.com/?flags=g®ex=(%3F!%5B%5Cd. % 5D * (% 5Cd)% 5B% 5Cd.% 5D *% 5C1)% 5E% 5B% 5Cd.% 5D% 2B% 24 & input = 1.1.1) e non riesco a capire perché Python dovrebbe essere diverso né posso provalo –

+0

@frb forse ha bisogno di un po 'di escape o '$ 1' invece di' \ 1' per i backreferences? Sono un regex-fan, non un pitone-guru. –

0

Utilizzando collections.Counter:

from collections import Counter 

def unique(seq): 
    return any(x > 1 for x in Counter(seq).values()) 

Questo funzionerà per qualsiasi sequenza, non solo stringhe.

E solo ora ho notato che non volevi convertire in stringhe ... non so perché, ma lascerò che la risposta rimanga.

+0

-1. Questo non è quello che stavo chiedendo. Per favore, leggi di nuovo la mia domanda. – pemistahl

Problemi correlati