◀ 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<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
int chunkSize = 3;

List<List<Integer>> 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<List<Integer>> chunked = Lists.partition(list, 3);

// Apache Commons Collections 4
import org.apache.commons.collections4.ListUtils;
List<List<Integer>> 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 => `
    <div class="row">
        ${row.map(p => `<div class="col">${p.name}</div>`).join("")}
    </div>
`).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) のような言語標準が最速

関連記事

子ページ

子ページはありません

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

最近更新/作成されたページ