2013-04-08 7 views

risposta

10

Stranamente, non v'è una procedura di built-in in Racket per trovare l'indice 0-based di un elemento in una lista (la procedura opposta fa esiste, si chiama list-ref). Tuttavia, non è difficile da implementare in modo efficiente:

(define (index-of lst ele) 
    (let loop ((lst lst) 
      (idx 0)) 
    (cond ((empty? lst) #f) 
      ((equal? (first lst) ele) idx) 
      (else (loop (rest lst) (add1 idx)))))) 

Ma c'è è una procedura simile a srfi/1, si chiama list-index e si può ottenere l'effetto desiderato passando i giusti parametri:

(require srfi/1) 

(list-index (curry equal? 3) '(1 2 3 4 5)) 
=> 2 

(list-index (curry equal? 6) '(1 2 3 4 5)) 
=> #f 

UPDATE

A partire da Racket 6.7, index-of fa ora parte della libreria standard. Godere!

+2

Quanto bizzarro. La mailing list racket-dev sarebbe lo sbocco appropriato per raccomandare questa funzione da aggiungere alla lingua? –

+1

Immagino ... ma non è un grosso problema dato che è così semplice da implementare. –

+1

@Maxwell Mi ero dimenticato di 'list-index'. Vedi la mia risposta aggiornata. –

6

Ecco una semplice implementazione:

(define (index-of l x) 
    (for/or ([y l] [i (in-naturals)] #:when (equal? x y)) i)) 

E sì, qualcosa di simile a questo dovrebbe essere aggiunto alla libreria standard, ma è solo un po 'difficile da fare in modo che nessuno ha ancora arrivati.

Si noti, tuttavia, che si tratta di una funzionalità che è molto rara utile - dal momento che gli elenchi vengono di solito presi come una sequenza che viene decostruita utilizzando solo l'idioma primo/resto anziché accedere direttamente agli elementi. Oltre a questo, se ne hai un uso e sei un principiante, allora la mia prima ipotesi sarà che stai usando male le liste. Dato che, l'aggiunta di una funzione di questo tipo rischia di far scattare tali neofiti rendendoli più accessibili. (Ma sarà ancora aggiunto, alla fine.)

0

Si può anche utilizzare una funzione incorporata 'member' che fornisce una sottolista che inizia con l'articolo richiesto o #f se l'elemento non esiste nell'elenco. Seguente mette a confronto le lunghezze di lista originale e sottolista restituiti da membro:

(define (indexof n l) 
    (define sl (member n l)) 
    (if sl 
     (- (length l) 
     (length sl)) 
     #f)) 

Per molte situazioni, uno potrebbe voler indici di tutte le occorrenze della voce dell'elenco. Si può ottenere un elenco di tutti gli indici nel modo seguente:

(define (indexes_of1 x l) 
    (let loop ((l l) 
      (ol '()) 
      (idx 0)) 
    (cond 
     [(empty? l) (reverse ol)] 
     [(equal? (first l) x) 
     (loop (rest l) 
      (cons idx ol) 
      (add1 idx))] 
     [else 
     (loop (rest l) 
      ol 
      (add1 idx))]))) 

For/list può essere utilizzato anche per questo:

(define (indexes_of2 x l) 
    (for/list ((i l) 
      (n (in-naturals)) 
      #:when (equal? i x)) 
    n)) 

Testing:

(indexes_of1 'a '(a b c a d e a f g)) 
(indexes_of2 'a '(a b c a d e a f g)) 

uscita:

'(0 3 6) 
'(0 3 6) 
+1

Per favore, non fare la cosa '-1' per segnalare che non c'è indice. È molto più chiaro e semplice se in questi casi restituisci '# false ', quindi è il modo più idiomatico di farlo. –

+0

Il codice è stato corretto. – rnso