Jak połączyć dwie listy?

15

Przepraszam, ale elisp nie jest mój najlepszy. Muszę połączyć w ten sposób dwie listy ciągów:

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

Cóż, kolejność nie jest ważna, więc napisałem ten kod:

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

Działa, ale zastanawiam się, czy istnieje funkcja, która już to robi.

Jakieś wskazówki? Z góry dziękuję.

Daniele
źródło
4
Zobacz Listy budowania węzłów instrukcji Elisp.
Drew
2
appendjest poprawną odpowiedzią tutaj, ale byłby to inny (destrukcyjny) sposób (setcdr (last a) b).
Sean Allred
1
Pracujesz nad listami? dash.el ! (-concat '(1) '(2 3) '(4)) ;; => '(1 2 3 4)
Ehvince
Nigdy nie używaj add-to-listw kodzie Lisp (mówi to w dokumentacji). Zamiast tego użyj push.
Radon Rosborough,

Odpowiedzi:

25

Możesz także użyć append.

(append '("a" "b" "c") '("d" "e" "f"))
John Kitchin
źródło
2
I,(nconc '("a" "b" "c") '("d" "e" "f"))
prawnik
1
Och, tak, rzeczywiście appendwydaje się tutaj lepiej.
JeanPierre,
nconc działa, ale jeśli przechowujesz listy w zmiennych, zostaną one zmodyfikowane przez nconc. Np. (Let ((a '(1 2 3)) (b' (3 4 5))) (nconc ab) a) zmodyfikuje zmienną.
John Kitchin,
1
FYI cl-concatenateużywa, appendgdy TYPE list, więc obie odpowiedzi dają ten sam wynik.
phils
Tak, to na pewno działa. Dziękujemy wszystkim za pomoc.
Daniele
3

concatenate to alias dla „cl-concatenate” w „cl.el”.

(łącz sekwencję TYPU ...)

Połącz w ciąg typu TYPE argument SEKWENCJE.

Na przykład

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

Ponieważ jest on zdefiniowany cl, być może będziesz musiał (require 'cl)najpierw, w przeciwnym razie możesz użyć tego, cl-concatenateco wydaje się być domyślnie załadowane.

Ponadto, jak wskazuje @phils, cl-concatenatepo prostu wywołuje, appendgdy TYPE 'list, oto źródło z 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))))

Jeśli więc używasz tylko list, łatwiej jest z nich korzystać bezpośrednio append, jak wskazał @John Kitchin.

Wreszcie @lawlist wspomniał nconc:

nconc to wbudowana funkcja w kodzie źródłowym „C”.

(LISTY nconc i rest)

Łącz dowolną liczbę list, zmieniając je. Tylko ostatni argument nie jest zmieniany i nie musi być listą.

Co to znaczy:

(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")
Jean Pierre
źródło
Dzięki, ale wygląda na to, że zwraca błąd, jeśli 2. i 3. argument są zmiennymi, a nie jawnymi listami.
Daniele
1
(setq l1 '("a" "b" "c") l2 '("d" "e" "f")) (concatenate 'list l1 l2)działa ok.
JeanPierre
@Daniele Podejrzewam, że próbowałeś zacytować zmienne, co oznacza, że ​​nie są one oceniane według wartości z listy. (tzn. varnamewolisz niż 'varname).
phils
Dla kompletności równie dobrze mogę wspomnieć o innym niż CL sposobie łączenia dowolnego typu sekwencji w Emacsie> = 25: seq-concatenate(po (require 'seq)), chociaż to z kolei po prostu się zawija cl-concatenate.
Basil,