Scheme: change value of an element in a list

2019-06-17 12:24发布

问题:

I hate using SO as a way to find simple functions, but I really can't find a function like this anywhere:

Given a list (1 2 3 4 5), I'd like the equivalent of (PHP's, Perl's, Python's)

$a = array(1, 2, 3, 4, 5);   
$a[3] = 100;  

Which results in (1 2 3 100 5)

Thanks!

回答1:

You can write list-set! of Guile, like so:

(define a (list 1 2 3 4))     ; a is '(1 2 3 4)

(define (list-set! list k val)
    (if (zero? k)
        (set-car! list val)
        (list-set! (cdr list) (- k 1) val)))

(list-set! a 2 100)           ; a is '(1 2 100 4)

(Tried this in DrRacket.)



回答2:

Using standard functions without any SRFI:

(set-car! (list-tail lst k) val)


回答3:

Guile has a built-in function called list-set! that does exactly what you want, using zero-based indices. For your example, you would have:

(define a '(1 2 3 4 5))
(list-set! a 3 100)

I don't think this is standard Scheme, however, and I don't know if it's really efficient. For a fixed-length array you should probably use a vector:

(define a2 #(1 2 3 4 5))
(vector-set! a2 3 100)

I'm pretty sure this is part of the language standard.



回答4:

I may be a bit late, but I have a different answer.

Part of the functional-program paradigm seems to be to try to avoid modifying data when possible. For efficiency reasons you may want to go with the other answers here. But otherwise, consider a non-mutating function such as this:

(define (list-with lst idx val)
  (if (null? lst)
    lst
    (cons
      (if (zero? idx)
        val
        (car lst))
      (list-with (cdr lst) (- idx 1) val))))

Which passes the following tests:

(describe "a function that returns a list with a 'changed' value"
  (it "can modify the edges of lists without having 1-off errors"
    (expect (list-with '(1 2 3 4 5) 0 99) (be equal? '(99 2 3 4 5)))
    (expect (list-with '(1 2 3 4 5) 4 99) (be equal? '(1 2 3 4 99))))
  (it "has something to do with creating new lists"
    (expect (list-with '(1 2 3 4 5) 2 99) (be equal? '(1 2 99 4 5))))
  (it "doesnt just modify the contents of the original list"
    (let ((a '(1 2 3 4 5)))
      (list-with a 2 99)
      (expect a (be equal? '(1 2 3 4 5))))))

(The code is written in Chicken Scheme and the tests with the "missbehave" library. But it seems like pretty portable Scheme.)



标签: list lisp scheme