2017-04-11 3 views
1

リストのリストをelispのインデックスでグループ化するにはどうすればよいですか?リストはorg-tableのような表を表しているので、各サブリストは行を表します。インデックスによるグループのテーブルまたはリストのグループ化

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

は、'((a 1 0) (b 1 1) (c 0 0))となる。

次に、ある列を別の列でグループ化できるようにしたいと考えています。たとえば、最初の列を3番目の列にグループ化すると、最初の行と3番目の行の3番目の列が0なので、'((0 a c) (1 b))と表示されます。

私は次のコードを試しましたが、 elispやより良い方法でグループ化機能がありますか?

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

答えて

1

は、リストのグループ要素は、group-by-eqと呼ばれることができElispCookbookの機能があるように起こります。この関数は、リストの各要素(「行」)に適用される関数fを受け取り、その値でリスト(「行」)をグループ化します。その機能を使用して

、我々はそれをnthを呼び出す機能を渡すことによって、列関数でグループを作成することができます。

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

をそして、あなたの質問には、二重のグループ化を要求するが、一度ちょうどグループしてみましょう:

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

まあ、私は2番目のグループがあったと思ったが、あなただけの各グループのn番目の要素を選択するように、それは、この場合には、最初の要素になります。

(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

アソシエーションリストの解決策が機能しない場合は、代わりにハッシュテーブルを使用することも、Lisp以外のものを使用することもできます。 – ashawley

関連する問題