Схема: изменить значение элемента в списке - PullRequest
7 голосов
/ 12 сентября 2011

Я ненавижу использовать SO как способ найти простые функции, но я действительно нигде не могу найти такую ​​функцию:

Учитывая список (1 2 3 4 5), я бы хотелэквивалент (PHP, Perl, Python)

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

Что приводит к (1 2 3 100 5)

Спасибо!

Ответы [ 4 ]

7 голосов
/ 12 сентября 2011

Вы можете написать list-set! из Guile, вот так:

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

(пробовал в DrRacket.)

3 голосов
/ 24 октября 2011

Возможно, я немного опоздал, но у меня другой ответ.

Часть парадигмы функциональной программы, кажется, пытается избежать изменения данных, когда это возможно.По соображениям эффективности вы можете пойти с другими ответами здесь.Но в противном случае рассмотрим функцию без мутаций, такую ​​как эта:

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

, которая проходит следующие тесты:

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

(код написан на схеме Chicken и тестах сбиблиотека "missbehave". Но это похоже на довольно переносимую схему.)

3 голосов
/ 12 сентября 2011

Использование стандартных функций без каких-либо SRFI:

(set-car! (list-tail lst k) val)
3 голосов
/ 12 сентября 2011

Guile имеет встроенную функцию под названием list-set!, которая делает именно то, что вы хотите, используя нулевые индексы.Для вашего примера вы должны иметь:

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

Я не думаю, что это стандартная схема, однако, и я не знаю, действительно ли она эффективна.Для массива фиксированной длины вам, вероятно, следует использовать вектор:

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

Я уверен, что это является частью языкового стандарта.

...