はじめに
webサービスを構築していく中で必要な知識を備忘録として残しております。
今回は 配列関数
について深堀りしていきたいと思います。
※随時writeしていきます。
現場でよく使う配列関数
配列関数 | 説明 | 使用頻度 |
---|---|---|
in_array | 配列の要素に特定の値を含むものがあるか | ★★★★★ |
count | 配列の要素の数を返す | ★★★★★ |
array_merge | 配列同士を結合(マージ)する | ★★★★ |
array_push | 配列の末尾に要素を追加する | ★★★ |
array_chunk | 配列を指定した要素を持つ配列に分解する | ★★★ |
array_column | 配列から特定単一カラムの配列を取得する | ★★★ |
in_array
概要
配列の要素に特定の値を含むものがあるかをチェックする関数
第一引数:配列内で検索される値
第二引数:検索対象の配列
第三引数:型チェックまで実施するかどうか(比較を厳密に行うかどうか)
戻り値:bool (true・false)
in_array(mixed $needle, array $haystack, bool $strict = false): bool
使用例
<?php
$colors = ['red', 'blue', 'orange'];
// -- 1
if(in_array('blue', $colors, true)) {
echo 'blueは配列内に存在します';
} else {
echo 'blueは配列内に存在しません';
}
// -- 2
if(in_array('black', $colors, true)) {
echo 'blackは配列内に存在します';
} else {
echo 'blackは配列内に存在しません';
}
?>
1 : blueは配列内に存在します
2 : blackは配列内に存在しません
多次元配列の場合
後に説明する array_column
を使用し判定処理を実施
<?php
$colors = [
['color' => 'red', 'number' => '1'],
['color' => 'blue', 'number' => '2'],
['color' => 'orange', 'number' => '3']
];
// -- 1
if(in_array('blue', array_column($colors, 'color'), true)) {
echo 'blueは配列内に存在します';
} else {
echo 'blueは配列内に存在しません';
}
// -- 2
if(in_array('black', array_column($colors, 'color'), true)) {
echo 'blackは配列内に存在します';
} else {
echo 'blackは配列内に存在しません';
}
?>
1 : blueは配列内に存在します
2 : blackは配列内に存在しません
代替ロジックとのパフォーマンス比較
in_array
VS array_search
VS isset
in_array
<?php
// 検証用10万テストデータ生成
$tests = [];
for( $i = 0; $i < 100000; ++$i ){
$tests[] = 'test' . '_'. $i;
}
$start = microtime(true);
if(in_array('test_99999', $tests, true)) {
$finished = true;
};
$end = microtime(true);
echo sprintf("%.6f",($end - $start)) . '秒';
?>
0.000694秒
array_search
<?php
// 検証用10万テストデータ生成
$tests = [];
for( $i = 0; $i < 100000; ++$i ){
$tests[] = 'test' . '_'. $i;
}
$start = microtime(true);
$key = array_search('test_99999', $tests);
if ($key !== false) {
$finished = true;
}
$end = microtime(true);
echo sprintf("%.6f",($end - $start)) . '秒';
?>
0.000582秒
isset
<?php
// 検証用10万テストデータ生成
$tests = [];
for( $i = 0; $i < 100000; ++$i ){
$tests[] = 'test' . '_'. $i;
}
$start = microtime(true);
// issetを使用するにはキーと値を反転させる必要がある
$tests = array_flip($tests);
if(isset($tests['test_99999'])) {
$finished = true;
};
$end = microtime(true);
echo sprintf("%.6f",($end - $start)) . '秒';
?>
0.004728秒
- 結果
in_array
とarray_search
は同等のパフォーマンス結果となった。
なので、パフォーマンス的にはどちらでも良いと思いますが、戻り値がそれぞれ違うため、状況に応じて使い分けが必要だと思います。
(in_array
: bool、array_search
: key値 or false)
isset
で判定する場合array_flip
をする必要があるため、その分遅くなっていた。
count
概要
配列やオブジェクトの要素数を数えるために使用する関数
第一引数:要素数を数える対象の配列やカウンタブルなオブジェクト
第二引数:デフォルトは COUNT_NORMAL
です。COUNT_RECURSIVE
を指定すると、多次元配列の場合に再帰的に要素を数えます
戻り値:int
count(mixed $array_or_countable, int $mode = COUNT_NORMAL): int
使用例
$colors = ['red', 'blue', 'orange'];
$count = count($colors);
echo "要素数: $count";
要素数: 3
多次元配列の場合
<?php
$colors = [
['color' => 'red', 'number' => '1'],
['color' => 'blue', 'number' => '2'],
['color' => 'orange', 'number' => '3'],
['color' => 'black', 'number' => '4']
];
$count = count($colors);
echo "要素数: $count";
?>
要素数: 4
- mode =
COUNT_RECURSIVE
<?php
$colors = [
['color' => 'red', 'number' => '1'],
['color' => 'blue', 'number' => '2'],
['color' => 'orange', 'number' => '3'],
['color' => 'black', 'number' => '4']
];
$count = count($colors, COUNT_RECURSIVE);
echo "要素数: $count";
?>
要素数: 12
要素数8 + 配列数4 で12とカウントされます。使い道はあまりなさそう。
代替ロジックとのパフォーマンス比較
count
VS sizeof
count
<?php
// 検証用10万テストデータ生成
$tests = [];
for( $i = 0; $i < 100000; ++$i ){
$tests[] = 'test' . '_'. $i;
}
$start = microtime(true);
$count = count($tests);
$end = microtime(true);
echo sprintf("%.6f",($end - $start)) . '秒';
?>
0.000001秒
sizeof
<?php
// 検証用10万テストデータ生成
$tests = [];
for( $i = 0; $i < 100000; ++$i ){
$tests[] = 'test' . '_'. $i;
}
$start = microtime(true);
$count = sizeof($tests);
$end = microtime(true);
echo sprintf("%.6f",($end - $start)) . '秒';
?>
0.000006秒
単純に配列の要素数を取得するのは count
がパフォーマンスが良い結果がでました。
array_merge
概要
複数の配列を結合するための関数
第一引数:結合する最初の配列
第二引数:結合する他の配列(複数指定可能)
戻り値:配列
array_merge(array $array1, array ...$arrays): array
使用例
<?php
$array1 = ["red", "blue"];
$array2 = ["orange"];
$mergedArray = array_merge($array1, $array2);
print_r($mergedArray);
?>
Array
(
[0] => red
[1] => blue
[2] => orange
)
連想配列の場合
<?php
$array1 = ["r" => "red", "b" => "blue"];
$array2 = ["o" => "orange"];
$array3 = ["w" => "white"];
$mergedArray = array_merge($array1, $array2, $array3);
print_r($mergedArray);
?>
Array
(
[r] => red
[b] => blue
[o] => orange
[w] => white
)
- 重複キーがある場合
<?php
$array1 = ["r" => "red", "b" => "blue"];
$array2 = ["o" => "orange"];
$array3 = ["b" => "black"];
$mergedArray = array_merge($array1, $array2, $array3);
print_r($mergedArray);
?>
Array
(
[r] => red
[b] => black
[o] => orange
)
キー:b
は二つ存在するが、blackで上書きされてしまう。
多次元配列の場合
<?php
$colors = [
['color' => 'red', 'number' => '1'],
['color' => 'blue', 'number' => '2'],
['color' => 'orange', 'number' => '3'],
['color' => 'black', 'number' => '4']
];
$colors2 = [
['color' => 'white', 'number' => '5'],
['color' => 'pink', 'number' => '6'],
];
$mergedArray = array_merge($colors, $colors2);
print_r($mergedArray);
?>
Array
(
[0] => Array
(
[color] => red
[number] => 1
)
[1] => Array
(
[color] => blue
[number] => 2
)
[2] => Array
(
[color] => orange
[number] => 3
)
[3] => Array
(
[color] => black
[number] => 4
)
[4] => Array
(
[color] => white
[number] => 5
)
[5] => Array
(
[color] => pink
[number] => 6
)
)
代替ロジックとのパフォーマンス比較
array_merge
VS + 演算子
VS array_merge_recursive
array_merge
<?php
// 検証用10万テストデータ1生成
$tests = [];
for( $i = 0; $i < 100000; ++$i ){
$tests[] = ['test' => $i];
}
// 検証用10万テストデータ2生成
$tests2 = [];
for( $i = 0; $i < 100000; ++$i ){
$tests2[] = ['test2' => $i];
}
$start = microtime(true);
$mergedArray = array_merge($tests,$tests2);
$end = microtime(true);
echo sprintf("%.6f",($end - $start)) . '秒';
?>
0.004547秒
+ 演算子
<?php
// 検証用10万テストデータ1生成
$tests = [];
for( $i = 0; $i < 100000; ++$i ){
$tests[] = ['test' => $i];
}
// 検証用10万テストデータ2生成
$tests2 = [];
for( $i = 0; $i < 100000; ++$i ){
$tests2[] = ['test2' => $i];
}
$start = microtime(true);
$mergedArray = $tests + $tests2;
$end = microtime(true);
echo sprintf("%.6f",($end - $start)) . '秒';
?>
0.003017秒
array_merge_recursive
<?php
// 検証用10万テストデータ1生成
$tests = [];
for( $i = 0; $i < 100000; ++$i ){
$tests[] = ['test' => $i];
}
// 検証用10万テストデータ2生成
$tests2 = [];
for( $i = 0; $i < 100000; ++$i ){
$tests2[] = ['test2' => $i];
}
$start = microtime(true);
$mergedArray = array_merge_recursive($tests,$tests2);
$end = microtime(true);
echo sprintf("%.6f",($end - $start)) . '秒';
?>
0.004963秒
すべて同等のパフォーマンスが出る結果となった。
ただし、今回はキー指定なしの多次元配列で検証したが、重複ありだと array_merge_recursive
のパフォーマンスが著しく落ちる結果も見られた。
また、キー重複ありの場合、array_merge
は上書きするに対して、+ 演算子
は最初の配列の値が優先されます。(先勝ち)
その特性も踏まえての使い分けが必要です。
array_push
概要
配列の末尾に一つ以上の要素を追加するための関数
第一引数:要素を追加する対象の配列(参照渡し)
第二引数:追加する要素。複数の要素を一度に追加することができます
戻り値:int (配列要素数)
array_push(array &$array, mixed $value1, mixed $value2, ...): int
使用例
<?php
$colors = ["red", "blue"];
array_push($colors, "orange", "black");
print_r($colors);
?>
Array
(
[0] => red
[1] => blue
[2] => orange
[3] => black
)
代替ロジックとのパフォーマンス比較
array_push
VS [] 演算子
array_push
<?php
// 検証用10万テストデータ1生成
$tests = [];
for( $i = 0; $i < 100000; ++$i ){
$tests["test_1_$i"] = 'test' . '_'. $i;
}
$start = microtime(true);
$results = [];
foreach ($tests as $test) {
array_push($results, $test);
}
$end = microtime(true);
echo sprintf("%.6f",($end - $start)) . '秒';
?>
0.006505秒
[] 演算子
<?php
// 検証用10万テストデータ1生成
$tests = [];
for( $i = 0; $i < 100000; ++$i ){
$tests["test_1_$i"] = 'test' . '_'. $i;
}
$start = microtime(true);
$results = [];
foreach ($tests as $test) {
$results[] = $test;
}
$end = microtime(true);
echo sprintf("%.6f",($end - $start)) . '秒';
?>
0.005865秒
array_push
と [] 演算子
が同等のパフォーマンスだが、[] 演算子
のほうが速い結果となった。
検証件数より多いデータ量だと差は開いていくので、パフォーマンス的には[] 演算子
を使用するほうが良いと言える。
array_chunk
概要
配列を指定されたサイズで分割するための関数
第一引数:分割する対象の配列
第二引数:各チャンクのサイズを指定します
第三引数:キーを保持するかどうかを指定するフラグ。デフォルトは false で、キーが再インデックス化されます
戻り値:配列
array_chunk(array $input, int $size, bool $preserve_keys = false): array
使用例
<?php
$colors = ['red','blue','orange','black','white','pink','yellow','green','brown'];
$chunks = array_chunk($colors, 3);
print_r($chunks);
?>
Array
(
[0] => Array
(
[0] => red
[1] => blue
[2] => orange
)
[1] => Array
(
[0] => black
[1] => white
[2] => pink
)
[2] => Array
(
[0] => yellow
[1] => green
[2] => brown
)
)
- 多次元配列の場合
$colors = [
['color' => 'red', 'number' => '1'],
['color' => 'blue', 'number' => '2'],
['color' => 'orange', 'number' => '3'],
['color' => 'black', 'number' => '4'],
['color' => 'white', 'number' => '5'],
['color' => 'pink', 'number' => '6'],
['color' => 'yellow', 'number' => '7'],
['color' => 'green', 'number' => '8'],
['color' => 'brown', 'number' => '9'],
];
$chunks = array_chunk($colors, 3);
print_r($chunks);
Array
(
[0] => Array
(
[0] => Array
(
[color] => red
[number] => 1
)
[1] => Array
(
[color] => blue
[number] => 2
)
[2] => Array
(
[color] => orange
[number] => 3
)
)
[1] => Array
(
[0] => Array
(
[color] => black
[number] => 4
)
[1] => Array
(
[color] => white
[number] => 5
)
[2] => Array
(
[color] => pink
[number] => 6
)
)
[2] => Array
(
[0] => Array
(
[color] => yellow
[number] => 7
)
[1] => Array
(
[color] => green
[number] => 8
)
[2] => Array
(
[color] => brown
[number] => 9
)
)
)
array_column
概要
多次元配列から指定した列(キー)の値だけを抽出して新しい配列を生成するための関数
第一引数:対象の多次元配列
第二引数:抽出したい列のキー。これは、連想配列の場合はキー、数値添字の場合はインデックスとなります
第三引数:新しい配列のインデックスとして使用する列のキー。省略すると数値添字が使用されます
戻り値:配列
aarray_column(array $input, mixed $column_key, mixed $index_key = null): array
使用例
<?php
$colors = [
['color' => 'red', 'number' => '1'],
['color' => 'blue', 'number' => '2'],
['color' => 'orange', 'number' => '3'],
['color' => 'black', 'number' => '4']
];
$color = array_column($colors, 'color');
print_r($color);
?>
Array
(
[0] => red
[1] => blue
[2] => orange
[3] => black
)
代替ロジックとのパフォーマンス比較
array_column
VS array_map
VS foreach
array_column
<?php
// 検証用10万テストデータ生成
$tests = [];
for( $i = 0; $i < 100000; ++$i ){
$tests[] = ['number' => $i , 'key' => 'test'. '_' .$i];
}
$start = microtime(true);
$color = array_column($tests, 'number');
$end = microtime(true);
echo sprintf("%.6f",($end - $start)) . '秒';
?>
0.004329秒
foreach
<?php
// 検証用10万テストデータ生成
$tests = [];
for( $i = 0; $i < 100000; ++$i ){
$tests[] = ['number' => $i , 'key' => 'test'. '_' .$i];
}
$start = microtime(true);
$numbers = [];
foreach ($tests as $test) {
$numbers[] = $test['number'];
}
$end = microtime(true);
echo sprintf("%.6f",($end - $start)) . '秒';
?>
0.014227秒
array_map
<?php
// 検証用10万テストデータ生成
$tests = [];
for( $i = 0; $i < 100000; ++$i ){
$tests[] = ['number' => $i , 'key' => 'test'. '_' .$i];
}
$start = microtime(true);
$color = array_map(function($test) {
return $test["number"];
}, $tests);
$end = microtime(true);
echo sprintf("%.6f",($end - $start)) . '秒';
?>
0.013517秒
array_column
がパフォーマンスが良い結果となった。
特定の要件を満たす場合は、シンプルで効果的といえます。