2017-04-11 7 views
1

Wie kann ich eine Liste von Listen nach einem bestimmten Index in elisp gruppieren? Die Listen stellen Tabellen wie Org-Tabellen dar, so dass jede Unterliste eine Zeile darstellt, z.Gruppentabellen oder Listen von Listen nach Index

| a | 1 | 0 | 
| b | 1 | 1 | 
| c | 0 | 0 | 

wäre '((a 1 0) (b 1 1) (c 0 0)).

Ich möchte in der Lage sein, dann eine bestimmte Spalte durch eine andere Spalte zu gruppieren. Also, zum Beispiel, Gruppierung der ersten Spalte durch die dritte, würde ich '((0 a c) (1 b)) erwarten, da die dritte Spalte der ersten und dritten Zeile ist 0.

Ich habe den folgenden Code versucht, aber es machen so viele Schleifen. Gibt es eine Gruppierungsfunktion in elisp oder besser?

;; group column1 by column2 in table 
(defun group-by (col1 col2 table) 
    (let ((vals (cl-remove-duplicates  ;find unique values to group by 
       (cl-loop for row in table 
        collect (nth col2 row))))) 
    (cl-loop for val in vals   ;for each unique value 
     collect (cons val (cl-loop for row in table ;check each row for match 
          when (eq val (nth col2 row)) 
          collect (nth col1 row)))))) 

(defvar tst-data '((a 1 0) (b 1 1) (c 0 0))) 
(group-by 0 2 tst-data) 
;; ((1 b) 
;; (0 a c)) 

Antwort

1

Es geschieht eine Funktion auf der ElispCookbook sein, die Gruppe Elemente einer Liste können, group-by-eq genannt. Diese Funktion wiederum verwendet eine Funktion f, die auf jedes Element ("Zeile") der Liste angewendet wird, und gruppiert dann die Liste ("Zeilen") um diesen Wert.

diese Funktion können wir eine Gruppe von Spaltenfunktion schreiben, indem es vorbei eine Funktion aufruft nth:

(defun group-by-col (n table) 
    (group-by-eq (lambda (row) (nth n row)) table)) 

Und Ihre Frage geht dahin, für eine Doppel Gruppierung, aber lassen Sie uns Gruppe nur einmal:

(let ((test-data '((a 1 0) 
        (b 1 1) 
        (c 0 0)))) 
    (mapcar 'cdr (group-by-col 2 test-data))) 
;; (((c 0 0) (a 1 0)) ((b 1 1))) 

Nun, ich dachte, dass es eine zweite Gruppierung war, aber dann sieht es aus wie Sie wollen einfach nur das n-te Element jeder Gruppe auswählen, in diesem Fall das erste Element:

(let ((test-data '((a 1 0) 
        (b 1 1) 
        (c 0 0)))) 
    (mapcar 
    (lambda (grp) 
    (cons (car grp) (mapcar (lambda (lst) (nth 0 lst)) (cdr grp)))) 
    (group-by-col 2 test-data))) 
;; ((0 c a) (1 b)) 
+0

Wenn die Assoziationslistenlösung nicht funktioniert, können Sie stattdessen auch Hashtabellen oder nur etwas anderes als Lisp verwenden, wenn Ihnen diese zur Verfügung steht. – ashawley

Verwandte Themen