How do I find the index of an element in a list in Racket?

前端 未结 3 626
爱一瞬间的悲伤
爱一瞬间的悲伤 2020-12-03 05:47

This is trivial implement of course, but I feel there is certainly something built in to Racket that does this. Am I correct in that intuition, and if so, what is the functi

相关标签:
3条回答
  • 2020-12-03 06:23

    Strangely, there isn't a built-in procedure in Racket for finding the 0-based index of an element in a list (the opposite procedure does exist, it's called list-ref). However, it's not hard to implement efficiently:

    (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))))))
    

    But there is a similar procedure in srfi/1, it's called list-index and you can get the desired effect by passing the right parameters:

    (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

    As of Racket 6.7, index-of is now part of the standard library. Enjoy!

    0 讨论(0)
  • 2020-12-03 06:33

    One can also use a built-in function 'member' which gives a sublist starting with the required item or #f if item does not exist in the list. Following compares the lengths of original list and the sublist returned by member:

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

    For many situations, one may want indexes of all occurrences of item in the list. One can get a list of all indexes as follows:

    (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 can also be used for this:

    (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))
    

    Output:

    '(0 3 6)
    '(0 3 6)
    
    0 讨论(0)
  • 2020-12-03 06:37

    Here's a very simple implementation:

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

    And yes, something like this should be added to the standard library, but it's just a little tricky to do so nobody got there yet.

    Note, however, that it's a feature that is very rarely useful -- since lists are usually taken as a sequence that is deconstructed using only the first/rest idiom rather than directly accessing elements. More than that, if you have a use for it and you're a newbie, then my first guess will be that you're misusing lists. Given that, the addition of such a function is likely to trip such newbies by making it more accessible. (But it will still be added, eventually.)

    0 讨论(0)
提交回复
热议问题