Home About Contact
TypeScript , Functional Programming , Underscore.js

リストを n 個ごとに分割する その4 TypeScript 編

React で名前の配列を4個ごとに区切ったサブリストをつくり、 それをテーブルのそれぞれ行として扱う必要が生じた。

リストを n 個ごとに分割する その3で 書いたコードを TypeScript に移植したので、その覚え書きです。

2025-07-09 update 結論だけ知りたい場合はこちらをご覧ください: リストを n 個ごとに分割する ファイナルアンサー

移植対象のコード

その3で書いたコードそのままです。

// main.kts

typealias TypeT = String
typealias TypeR = List<List<String>>

val toSubListList: (List<String>, Int)->TypeR = { list, n->
    val initial: TypeR = listOf(listOf())
    
    val operation: (TypeR, TypeT)->TypeR = { acc, itemValue->
        if( acc.isEmpty() ){ 
            val newSubList = listOf(itemValue)
            acc + listOf(newSubList)
        } else {
            val lastSubList = acc.last()
            if( lastSubList.size < n ){
                val newSubList = lastSubList + listOf(itemValue)
                acc.take( acc.size-1 ) + listOf(newSubList)
            } else {
                val newSubList = listOf(itemValue)
                acc + listOf(newSubList)
            }
        }
    }

    list.fold(initial, operation)
}

val list = listOf("1","2","3","4","5","6","7","8")
println(toSubListList(list, 2)) // [[1, 2], [3, 4], [5, 6], [7, 8]]
println(toSubListList(list, 3)) // [[1, 2, 3], [4, 5, 6], [7, 8]]
println(toSubListList(list, 4)) // [[1, 2, 3, 4], [5, 6, 7, 8]]
println(toSubListList(list, 5)) // [[1, 2, 3, 4, 5], [6, 7, 8]]

これを TypeScript に書き直します。

TypeScript 版 toSubListList

TypeScript を実行するのに deno を使います。

環境の確認:

$ deno --version
deno 2.4.1 (stable, release, x86_64-unknown-linux-gnu)
v8 13.7.152.6-rusty
typescript 5.8.3

underscore.js を使いたかったのですが、 deno でそれを使う方法がすぐにわからなかったので、 代わりに lodash を使うことにします。

次のようにすることで使えました。

$ deno add npm:lodash
Add npm:lodash@4.17.21

main.ts を次のように書いて動作確認:

import _ from 'lodash'

const sum = _.reduce([1, 2, 3], function(memo, num){ return memo + num; }, 0)
console.log(sum)
$ deno run main.ts
$ deno main.ts

としても普通に実行できた。

それではこれで toSubListList 関数を書いていこう。

単に移植しただけで特別なことは何もしていない。

// main.ts
import _ from 'lodash'

const toSubListList = (list: string[], n: number) => {
    const isEmpty = (listList: string[][]): boolean => {
        return (listList.length===0)
    }
    
    const take = (listList: string[][], n: number): string[][] => {
        if (isEmpty(listList)) {
            return []
        } else {
            return listList.slice(0, n)
        }
    }
    
    const initialValue: string[][] = []
    
    return _.reduce(list, (acc: string[][], item: string)=> {
        if (isEmpty(acc)) {
            const newSubList = [item]
            return acc.concat([newSubList])
        } else {
            const lastSubList: string[] = _.last(acc)
            if (lastSubList.length < n) {
                const newSubList = lastSubList.concat([item])
                return take(acc, acc.length-1).concat([newSubList])
            } else {
                const newSubList = [item]
                return acc.concat([newSubList])
            }
        }
    }, initialValue)
}

const list = ["1","2","3","4","5","6","7","8"]
console.log( toSubListList(list, 2) )
console.log( toSubListList(list, 3) )
console.log( toSubListList(list, 4) )
console.log( toSubListList(list, 5) )
$ deno main.ts
[ [ "1", "2" ], [ "3", "4" ], [ "5", "6" ], [ "7", "8" ] ]
[ [ "1", "2", "3" ], [ "4", "5", "6" ], [ "7", "8" ] ]
[ [ "1", "2", "3", "4" ], [ "5", "6", "7", "8" ] ]
[ [ "1", "2", "3", "4", "5" ], [ "6", "7", "8" ] ]

このままでは 要素が string のサブリストしか作成できなくて 不都合だったので、ジェネリックにしました。 T と書いただけです。

import _ from 'lodash'

//function toSubListList<T>(list: T[], n: number){
const toSubListList = <T>(list: T[], n: number): T[][] => {

    const isEmpty = (listList: T[][]): boolean => {
        return (listList.length===0)
    }
    
    const take = (listList: T[][], n: number): T[][] => {
        if (isEmpty(listList)) {
            return []
        } else {
            return listList.slice(0, n)
        }
    }
    
    const initialValue: T[][] = []
    
    return _.reduce(list, (acc: T[][], item: T)=> {
        if (isEmpty(acc)) {
            const newSubList = [item]
            return acc.concat([newSubList])
        } else {
            const lastSubList = _.last(acc)
            if (lastSubList.length < n) {
            //if (lastSubList!==undefined && lastSubList.length < n) {
                const newSubList = lastSubList.concat([item])
                return take(acc, acc.length-1).concat([newSubList])
            } else {
                const newSubList = [item]
                return acc.concat([newSubList])
            }
        }
    }, initialValue)
}

const list = ["1","2","3","4","5","6","7","8"]
console.log( toSubListList(list, 2) )
console.log( toSubListList(list, 3) )
console.log( toSubListList(list, 4) )
console.log( toSubListList(list, 5) )

これでリストの要素の型が string 以外でもサブリストにできます。

時間ができたら具体的な例を書きます。 それから lodash ではなく underscore.js を使った場合も書く予定。

かきかけです。