Home About
Golang , Groovy , Node.js

Groovy / Golang / Node.js, リストを n 個ごとに分割したリストのリスト(サブリスト)をつくりたい

このサイトのエントリーを全部取得してリストにして、それをたとえば10エントリーごとに分けてページネーションしたい、のような場合の話。 元のリストから n個ごとに分割したサブリストをつくりたい、というケースは結構ある。

Groovy

groovy で表現すればどうなるか。

main.groovy

def list = "a b c d e f g h i j k l m n o p q r s t u v w x y z".split(/ /)

int columnCount = 10
def rowList = []
while( list.size()>0 ){
    def cellList = list.take(columnCount)
    rowList << cellList
    list = list.drop(columnCount)
}
println rowList

この take, drop を使うことで簡単にサブリストをつくることができる。 (たぶん、もっと良い方法があるとは思うけど)

実行すると、以下のようになる。

$ groovy main
[[a, b, c, d, e, f, g, h, i, j], [k, l, m, n, o, p, q, r, s, t], [u, v, w, x, y, z]]

Golang

これをそのまま Golang で表現しようと思ったが、まだ Golang 力が足りない。 取り急ぎ、for ループで地道に実装した。

main.go

package main

import (
	"fmt"
	"strings"
)

func main() {
	list := strings.Split("a b c d e f g h i j k l m n o p q r s t u v w x y z", " ")

	columnCount := 10
	rowCount := (len(list) / columnCount) + 1

	rowList := [][]string{}
	for rowIndex := 0; rowIndex < rowCount; rowIndex++ {
		cellList := []string{}
		for columnIndex := 0; columnIndex < columnCount; columnIndex++ {
			index := rowIndex*columnCount + columnIndex
			if index < len(list) {
				cellList = append(cellList, list[index])
			}
		}

		if len(cellList) > 0 {
			rowList = append(rowList, cellList)
		}
	}

	fmt.Println(rowList)
}

変数名の rowList や cellList はテーブル(またはスプレッドシート)をイメージした変数名です。 リストを n 個に分割するとき、 n 列 x (len(リスト)/n+1)行 のテーブルに変形することを頭の中で想像する。

実行する。

$ go run main.go
[[a b c d e f g h i j] [k l m n o p q r s t] [u v w x y z]]

できた。

とりあえずは、目的を果たしたので、今日はこれまで。

追記 Node.js

Node.js でも書いたので、メモしておく。

package.json:

{
  "name": "my-sublist",
  "version": "1.0.0",
  "description": "",
  "main": "main.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "underscore": "^1.13.1"
  }
}

main.js:

sublist という再帰関数を書いた。

const _ = require('underscore');

const sublist = (accum, list, n)=> {
    if( list.length==0 ){
        return accum;
    } else {
        accum.push( _.take(list, n) );
        return sublist(accum, _.drop(list, n), n);
    }
};

const list = "a b c d e f g h i j k l m n o p q r s t u v w x y z".split(/ /);
const list2 = sublist([], list, 10);
console.log(list2);

実行する

$ node main.js
[
  [
    'a', 'b', 'c', 'd',
    'e', 'f', 'g', 'h',
    'i', 'j'
  ],
  [
    'k', 'l', 'm', 'n',
    'o', 'p', 'q', 'r',
    's', 't'
  ],
  [ 'u', 'v', 'w', 'x', 'y', 'z' ]
]

まてまて、sublist 関数の最初の引数はかならず [] なのだから、それを省略できるようにしよう。

const sublist = (list0, n0)=> {

    const recur = (accum, list, n)=> {
        if( list.length==0 ){
            return accum;
        } else {
            accum.push( _.take(list, n) );
            return recur(accum, _.drop(list, n), n);
        }
    };

    return recur([], list0, n0);
};


const list = "a b c d e f g h i j k l m n o p q r s t u v w x y z".split(/ /);
const list2 = sublist(list, 10);
console.log(list2);

以上。