10.

NumPy で 1 次元配列を多次元配列に変換 (reshape)

編集
この記事の要点
  • 1 次元配列を多次元配列(2 次元等)に変換する方法
  • JavaScript: Array.from({length: Math.ceil(arr.length / N)}, (_, i) => arr.slice(i * N, (i + 1) * N))
  • PHP: array_chunk($arr, $size) 一発
  • Python: [arr[i:i+n] for i in range(0, len(arr), n)]
  • 逆変換は flat() (JS) / array_merge(...) (PHP) / itertools.chain (Python)

 

JavaScript

方法 1: Array.from + slice

const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const chunkSize = 3;

const chunked = Array.from(
    { length: Math.ceil(arr.length / chunkSize) },
    (_, i) => arr.slice(i * chunkSize, (i + 1) * chunkSize)
);
// → [[1,2,3], [4,5,6], [7,8,9], [10]]

方法 2: reduce

const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const chunkSize = 3;

const chunked = arr.reduce((acc, val, i) => {
    const groupIndex = Math.floor(i / chunkSize);
    if (!acc[groupIndex]) acc[groupIndex] = [];
    acc[groupIndex].push(val);
    return acc;
}, []);
// → [[1,2,3], [4,5,6], [7,8,9], [10]]

方法 3: while ループ

function chunk(arr, size) {
    const result = [];
    for (let i = 0; i < arr.length; i += size) {
        result.push(arr.slice(i, i + size));
    }
    return result;
}
chunk([1,2,3,4,5,6,7,8,9,10], 3);

方法 4: lodash

import _ from "lodash";
_.chunk([1,2,3,4,5,6,7,8,9,10], 3);
// → [[1,2,3], [4,5,6], [7,8,9], [10]]

PHP

// array_chunk が標準で用意されている
$arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
$chunked = array_chunk($arr, 3);
// → [[1,2,3], [4,5,6], [7,8,9], [10]]

// キーを保持
$assoc = ['a' => 1, 'b' => 2, 'c' => 3, 'd' => 4];
$chunked = array_chunk($assoc, 2, true);
// → [["a"=>1, "b"=>2], ["c"=>3, "d"=>4]]

// 連想配列にも対応
$users = [
    ['name' => 'Alice'],
    ['name' => 'Bob'],
    ['name' => 'Carol'],
    ['name' => 'Dave'],
];
$pages = array_chunk($users, 2);
// → [[Alice, Bob], [Carol, Dave]]

Python

# リスト内包表記
arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
n = 3
chunked = [arr[i:i+n] for i in range(0, len(arr), n)]
# → [[1,2,3], [4,5,6], [7,8,9], [10]]

# itertools (より高機能)
from itertools import islice
def chunked(iterable, n):
    it = iter(iterable)
    while batch := list(islice(it, n)):
        yield batch

list(chunked([1,2,3,4,5,6,7,8,9,10], 3))

# more_itertools (3rd party)
from more_itertools import chunked
list(chunked([1,2,3,4,5,6,7,8,9,10], 3))

# numpy (行列として)
import numpy as np
arr = np.arange(1, 13)
matrix = arr.reshape(3, 4)
# → [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]

Java

// Java 8+ Stream
import java.util.*;
import java.util.stream.*;

List list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
int chunkSize = 3;

List> chunked = IntStream.range(0, (list.size() + chunkSize - 1) / chunkSize)
    .mapToObj(i -> list.subList(i * chunkSize, Math.min((i+1) * chunkSize, list.size())))
    .collect(Collectors.toList());

// Guava
import com.google.common.collect.Lists;
List> chunked = Lists.partition(list, 3);

// Apache Commons Collections 4
import org.apache.commons.collections4.ListUtils;
List> chunked = ListUtils.partition(list, 3);

逆変換(多次元 → 1 次元)

JavaScript

const nested = [[1,2,3], [4,5,6], [7,8,9]];

// flat()
const flat = nested.flat();
// → [1,2,3,4,5,6,7,8,9]

// 深いネストも
const deep = [[1, [2, 3]], [4, [5, 6]]];
deep.flat(Infinity);
// → [1, 2, 3, 4, 5, 6]

// 古い書き方
[].concat(...nested);
nested.reduce((a, b) => a.concat(b), []);

PHP

$nested = [[1,2,3], [4,5,6], [7,8,9]];

// array_merge
$flat = array_merge(...$nested);
// → [1,2,3,4,5,6,7,8,9]

// 深いネストは再帰
function flatten($arr) {
    $result = [];
    array_walk_recursive($arr, function($v) use (&$result) {
        $result[] = $v;
    });
    return $result;
}

Python

nested = [[1,2,3], [4,5,6], [7,8,9]]

# リスト内包
flat = [x for sub in nested for x in sub]

# itertools.chain
from itertools import chain
flat = list(chain.from_iterable(nested))

# numpy
import numpy as np
flat = np.array(nested).flatten()

応用: 表形式データの変換

1 次元 → 表(行 x 列)に分割

// 商品リストを 3 列のグリッド表示用に
const products = [
    {id: 1, name: 'A'}, {id: 2, name: 'B'},
    {id: 3, name: 'C'}, {id: 4, name: 'D'},
    {id: 5, name: 'E'}, {id: 6, name: 'F'},
    {id: 7, name: 'G'}
];

const rows = Array.from(
    { length: Math.ceil(products.length / 3) },
    (_, i) => products.slice(i * 3, (i + 1) * 3)
);

// HTML 出力
rows.map(row => `
    
${row.map(p => `
${p.name}
`).join("")}
`).join("");

ページネーション風に分割

// 1000 件のデータを 1 ページ 20 件で分割
const allItems = [...]; // 1000 件
const pageSize = 20;

function getPage(items, pageNumber, pageSize) {
    const start = (pageNumber - 1) * pageSize;
    return items.slice(start, start + pageSize);
}

const page1 = getPage(allItems, 1, 20);  // 0-19
const page2 = getPage(allItems, 2, 20);  // 20-39

// PHP の array_chunk と equivalent
const allPages = Array.from(
    { length: Math.ceil(allItems.length / pageSize) },
    (_, i) => allItems.slice(i * pageSize, (i + 1) * pageSize)
);

2 次元 → 3 次元(行列の分割)

// 行列を 2 x 2 のサブ行列に分割
const matrix = [
    [1, 2, 3, 4],
    [5, 6, 7, 8],
    [9, 10, 11, 12],
    [13, 14, 15, 16]
];

const subSize = 2;
const subMatrices = [];
for (let i = 0; i < matrix.length; i += subSize) {
    for (let j = 0; j < matrix[i].length; j += subSize) {
        const sub = matrix.slice(i, i + subSize).map(row => row.slice(j, j + subSize));
        subMatrices.push(sub);
    }
}
// → [
//   [[1,2],[5,6]],   [[3,4],[7,8]],
//   [[9,10],[13,14]], [[11,12],[15,16]]
// ]

注意点

  • 余り処理: 配列長が chunk size で割り切れないと最後だけ要素少なめ
  • メモリ効率: 大量データなら slice ではなく iterator / generator 使う
  • 元配列の変更: slice / array_chunk は新配列を返す(元は変更されない)
  • パフォーマンス: array_chunk (PHP) / partition (Guava) のような言語標準が最速

関連記事

編集
Post Share
子ページ

子ページはありません

同階層のページ
  1. 配列の作成
  2. 多次元配列の作成
  3. 要素の参照
  4. 要素の追加
  5. 要素の更新
  6. 要素の削除
  7. ブロードキャスト
  8. 多次元配列の構造の確認
  9. 多次元配列を1次元配列に変換
  10. 1次元配列を多次元配列に変換
  11. 要素の範囲指定
  12. 平均値の算出
  13. 行列を結合する方法