リストを n 個ごとに分割する ファイナルアンサー の応用例です。
ポケモンリストをHTMLテーブルに変換するのですが、 クライアントブラウザの幅に応じて 3列とか5列に切り替えたいとする・・・ということを考えます。
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 add npm:underscore
それではコードを書きます。
//
// main.ts
//
import _ from 'underscore'
const take = <T>(n: number, l: T[]) => {
return l.slice(0, n)
}
const drop = <T>(n: number, l: T[]) => {
return l.slice(n)
}
const group = <T>(n: number, l: T[]) => {
if (l.length==0) {
return []
} else {
return [take(n, l)].concat( group(n, drop(n,l)) )
}
}
ここまでは前回書いたコード。 そしてこの group を使って ポケモン名のリストから HTML テーブルを生成するための関数 toHtml を書きます。
const toHtml = (n: number, pokemonNameList: string[]): string => {
const pokemonListList = group(n, pokemonNameList)
const tableBody: string[][] = pokemonListList.map((pokemonList)=>{
const row: string[] = pokemonList.map((pokemon)=> {
return `<td>${pokemon}</td>`
})
return ['<tr>'].concat( row ).concat(['</tr>'])
})
return ['<table><tbody>'].concat( _.flatten(tableBody) ).concat( ['</tbody></table>'] ).join('\n')
}
たとえば、3列のテーブルを出力したい場合:
const list = [
'eevee',
'pidgeot',
'pikachu',
'voltorb',
'squirtle',
'golduck',
'charmander',
'golem',
'charizard',
'metapod',
'butterfree']
console.log(toHtml(3, list))
deno run します。
$ deno run main.ts
出力されたHTML:
<table><tbody>
<tr>
<td>eevee</td>
<td>pidgeot</td>
<td>pikachu</td>
</tr>
<tr>
<td>voltorb</td>
<td>squirtle</td>
<td>golduck</td>
</tr>
<tr>
<td>charmander</td>
<td>golem</td>
<td>charizard</td>
</tr>
<tr>
<td>metapod</td>
<td>butterfree</td>
</tr>
</tbody></table>
できました。
ブラウザでレンダリングするとこんな感じ:
今度は 5列を指定して出力してみます。
console.log(toHtml(5, list))
出力されたHTML:
<table><tbody>
<tr>
<td>eevee</td>
<td>pidgeot</td>
<td>pikachu</td>
<td>voltorb</td>
<td>squirtle</td>
</tr>
<tr>
<td>golduck</td>
<td>charmander</td>
<td>golem</td>
<td>charizard</td>
<td>metapod</td>
</tr>
<tr>
<td>butterfree</td>
</tr>
</tbody></table>
ブラウザでレンダリングするとこんな感じ:
以上です。