Как объединить два списка?

15

Извините, но элисп не мой лучший. Мне нужно объединить два списка строк следующим образом:

("a" "b" "c") + ("d" "e" "f") -> ("a" "b" "c" "d" "e" "f")

Ну, порядок не важен, поэтому я написал этот код:

(while lista
  (add-to-list 'listb (car lista)) 
  (setq lista (cdr lista)))

Это работает, но мне интересно, есть ли функция, которая уже делает это.

Любая подсказка? Заранее спасибо.

Daniele
источник
4
См. Раздел Создание списков узлов в руководстве по Elisp.
Дрю
2
appendэто правильный ответ здесь, но другой (разрушительный) способ сделать это будет (setcdr (last a) b).
Шон Оллред
1
Работаете со списками? dash.el ! (-concat '(1) '(2 3) '(4)) ;; => '(1 2 3 4)
Эвинс
Никогда не используйте add-to-listв коде на Лиспе (это сказано в строке документации). Вместо этого используйте push.
Радон Росборо

Ответы:

25

Вы также можете просто использовать приложение.

(append '("a" "b" "c") '("d" "e" "f"))
Джон Китчин
источник
2
И,(nconc '("a" "b" "c") '("d" "e" "f"))
юрист
1
О, да, действительно, appendкажется, здесь лучше.
ЖанПьер
nconc работает, но если вы храните списки в переменных, они будут изменены nconc. Например, (let ((a '(1 2 3)) (b' (3 4 5))) (nconc ab) a) изменит переменную a.
Джон Китчин
1
FYI cl-concatenateиспользует appendкогда TYPE list, так что оба ответа дают одинаковый результат.
Фил
Да, это, безусловно, делает работу. Большое спасибо всем за вашу помощь.
Даниэле
3

concatenate - это псевдоним cl-concatenate в cl.el.

(объединить ПОСЛЕДОВАТЕЛЬНОСТЬ ТИПА ...)

Объединить в последовательность типа TYPE аргумент SEQUENCEs.

Так что для вашего примера

(concatenate 'list '("a" "b" "c") '("d" "e" "f"))

Поскольку это определено в clвас, возможно, придется (require 'cl)сначала, в противном случае вы можете использовать, cl-concatenateкоторый, кажется, загружен по умолчанию.

Кроме того, как указывает @phils, cl-concatenateпросто вызывает, appendкогда TYPE есть 'list, вот источник из cl-extra.el:

(defun cl-concatenate (type &rest sequences)
  "Concatenate, into a sequence of type TYPE, the argument SEQUENCEs.
\n(fn TYPE SEQUENCE...)"
  (pcase type
    (`vector (apply #'vconcat sequences))
    (`string (apply #'concat sequences))
    (`list (apply #'append (append sequences '(nil))))
    (_ (error "Not a sequence type name: %S" type))))

Так что, если вы используете только списки, проще использовать напрямую append, как указал @John Kitchin.

Наконец, @lawlist упомянул nconc:

nconc - это встроенная функция в «C исходном коде».

(nconc & rest LISTS)

Объединить любое количество списков, изменив их. Только последний аргумент не изменяется и не обязательно должен быть списком.

Что это значит:

(nconc '("a" "b" "c") '("d" "e" "f"))
=> ("a" "b" "c" "d" "e" "f")

(setq l1 '("a" "b" "c")
      l2 '("d" "e" "f"))
(nconc l1 l2)
=> ("a" "b" "c" "d" "e" "f")
l1
=> ("a" "b" "c" "d" "e" "f")
l2
=> ("d" "e" "f")
JeanPierre
источник
Спасибо, но похоже, что он возвращает ошибку, если 2-й и 3-й аргументы являются переменными, а не явными списками.
Даниэль
1
(setq l1 '("a" "b" "c") l2 '("d" "e" "f")) (concatenate 'list l1 l2)работает нормально
ЖанПьер
@Daniele Я подозреваю, что вы пытались заключить в кавычки переменные, что означает, что они не оцениваются в их значениях списка. (т.е. вы хотите, varnameа не 'varname).
Фил
Для полноты я мог бы также упомянуть не-CL способ конкатенации любого типа последовательности в Emacs> = 25: seq-concatenate(после (require 'seq)), хотя это, в свою очередь, просто переносит cl-concatenate.
Василий