Help us understand the problem. What is going on with this article?

PHP配列処理大全

競技プログラミングで配列を操作することが多いので内部関数をまとめました。

目次

配列の結合
+演算子で結合する際の注意
文字列を配列にする
配列を文字列にする
配列に値が存在するか確認する
配列の並べ替え
配列を逆順にする
配列の先頭に値を追加する
配列の末尾に値を追加する
配列の指定箇所に値を追加する
配列の指定箇所を取り除く
配列の指定箇所を置き換える
配列の一部を取り出す
配列の値を別の変数に代入する
配列から条件に合うデータだけを抜き出して配列にする
配列を一括処理する
連想配列を値で並べ替える
連想配列を添え字で並び替える

配列の結合

array_merge()関数かarray_merge_recursive()関数+演算子も使える

array_merge()関数では前の配列に後ろの配列を追加した配列を返す
数値添え字の配列を結合する際、前の配列と後ろの配列は上書きされないように結合される
結合結果の数値添え字は振り直される
連想配列を結合する時に、添え字が重複した場合は後の配列で上書きされる

array_merge_recursive()関数はarray_merge()関数とほぼ同じ
連想配列の結合を行う時に添字が重複した場合はネストを一段深くして値を残すところが異なる

+演算子による結合は配列の種類にかかわらず、添字が重複した場合は前の配列を優先して結合する

example.php
<?php
$arr1 = ['a'];
$arr2 = ['A', 10 => 'B'];
array_merge($arr1, $arr2);
/*
  0 => 'a',
  1 => 'A',
  2 => 'B'
 */
array_merge_recursive($arr1, $arr2);
/*
  0 => 'a',
  1 => 'A',
  2 => 'B'
 */
$arr1 + $arr2;
/*
  0 => 'a',
  10 => 'B'
 */
//-------------------------

$arr1 = ['a' => 1];
$arr2 = ['a' => 'A', 'b' => 'B'];

array_merge($arr1, $arr2);
/*
  'a' => 'A',
  'b' => 'B'
 */
array_merge_recursive($arr1, $arr2);
/*
  'a' => [0 => 1, 1 => 'A'],
  'b' => 'B'
 */
$arr1 + $arr2;
/*
  'a' => 1,
  'b' => 'B'
 */

+演算子で結合する際の注意

連想配列の添字が数字として判定できる場合は数値にキャストされるので
'1'と1は同じ添字として処理される

文字列を配列にする

$target = 'a,b,c,d,e';
explode(',', $target); //['a', 'b', 'c', 'd', 'e']

配列を文字列にする

$target = ['a', 'b', 'c', 'd', 'e'];
implode(',', $target); //'a,b,c,d,e'

配列に値が存在するか確認する

in_array()関数や、array_search()関数を使う
in_array()関数を使用した場合、返り値はbool
array_search()関数を使用した場合、最初に見つけた要素の添え字を返し
存在しなかった場合はfalseを返す

注意
array_search()関数の戻り値を判定するときは===を必ず使う
==を使った場合0がfalseと同じ値だと判断されてしまう可能性があるから
<?php
$arr = ['a', 'b', 'c'];
in_array('a', $arr); //true
array_search('a', $arr); //0

配列の並べ替え

sort()関数、rsort()関数を使う
sort()関数は昇順、rsort()関数は降順に並び替える
第二引数は省略可能だが、数値として並び替えるSORT_NUMERICか文字列として並び替えるSORT_STRINGのどちらかを指定する方が良い
これらの関数は与えられた配列を直接操作し、添字が数値で振り直される
返り値はbool
直感的にわかると思うのでコード省略

配列を逆順にする

array_reverse()関数を使う
多次元配列の場合はネストの内側の配列は並び替えてくれない
並び替えと同時に数値添え字を0から振り直す
元の数値の添字を保持しておきたい場合は第二引数trueを指定する
連想配列の場合は第二引数を指定しても添字は振り直されない

<?php
$arr = ['a', 'b', 'c'];
array_reverse($arr); //[0 => 'c', 1 => 'b', 2 => 'a']
array_reverse($arr, true); //[2 => 'c', 1 => 'b', 0 => 'a']
//--------------------------------------------------

$arr = [
    'a' => 10,
    'b' => 20,
    'c' => 30,
];
array_reverse($arr); //['c' => 30, 'b' => 20, 'a' => 10]
array_reverse($arr, true); //同じ
//--------------------------------------------------

$arr = [
    10,
    [
        'A' => 1,
        'B' => 2,
        'C' => 3,
    ],
    'ABC',
];
array_reverse($arr); //[0 => 'ABC', 1 => ['A' => 1, 'B' => 2, 'C' => 3], 2 => 10]
array_reverse($arr, true); //[2 => 'ABC', 1 => ['A' => 1, 'B' => 2, 'C' => 3], 0 => 10]

配列の先頭に値を追加する

array_unshift()関数を使う
値を追加すると0からの連番で添字が振り直される
また配列を直接操作する
連想配列に対しても使えるが追加する要素の添字は0になる

<?php
$arr = ['a', 'b', 'c'];
array_unshift($arr, 'added'); //[0 => 'added', 1 => 'a', 2 => 'b', 3 => 'c']

配列の末尾に値を追加する

添字を指定せずに[]をつけて値を代入する

<?php
$arr[] = 'abc';

連想配列の末尾に値を追加する場合は通常通り

$arr['test'] = 'example';

array_push()関数を使うこともできるが関数を呼び出す分のコストがかかってしまうのであまりパフォーマンスが良くない
参考記事
https://qiita.com/kapitan/items/47d89449f23bc7f7c9bb

配列の指定箇所に値を追加する

array_splice()関数を使う

array_splice($arr, $offset, 0, $value);

第二引数に負の数を指定すると末尾からの位置指定になる
第四引数で配列を指定すると複数の値を一気に追加できる
配列の数字添字は振り直しになって、配列は直接操作されます

<?php
$arr = ['a', 'b', 'c'];
$value = 'added';
array_splice($arr, 1, 0, $value); //[0 => 'a', 1 => 'added', 2 => 'b', 3 => 'c']

配列の指定箇所を取り除く

同様にarray_splice()を使う
配列、開始位置、要素数を引数にとって返り値には取り除かれた値の配列が代入される

$removed_value = array_splice($arr, $offset, $count);
<?php
$arr = ['a', 'b', 'c'];
array_splice($arr, 1, 2); //['a']

配列の指定箇所を置き換える

同様にarray_splice()を使う
配列、開始位置、要素数、新しい値を引数にとって戻り値には抽出された値の配列が代入される

$replaced_value = array_splice($arr, $offset, $count, $value);
$arr = ['a', 'b', 'c'];
array_splice($arr, 1, 2, 'x'); //['a', 'x', 'x']

配列の一部を取り出す

array_slice()関数を使う
array_slice()関数は配列の一部を切り出して、新しい配列を返り値として返す
ただ、元の配列から要素が削除されてしまうことはないのがarray_splice()関数と違うところ!

$sliced_arr = array_slice($arr, $offset[, $count]);

第三引数は省略可能

<?php
$arr = ['a', 'b', 'c'];
$sliced_arr = array_slice($arr, 1); //['a']
#配列の値を別の変数に代入する

配列から条件に合うデータだけを抜き出して配列にする

array_filter()関数を使う
指定した条件に合致する要素のみを新しい配列にして返す

<?php
$filetered_arr = array_filter($arr, 'callback');

function callback($value): bool
{
    return true; //false
}

コールバック関数にはユーザー定義関数はもちろん、内部関数も使うことができる
ただ、関数で実現できない、言語構造を指定することはできない
例えばisset()とか

<?php
$arr = range(2, 50);
function isOdd($value): bool
{
    if (!is_int($value)) return false;
    return ($value % 2 != 0);
}
function isEven($value): bool
{
    if (!is_int($value)) return false;
    return ($value % 2 == 0);
}
$odd_arr = array_filter($arr, 'isOdd');
$even_arr = array_filter($arr, 'isEven');

配列を一括処理する

array_walk()関数かarray_map()関数を使う

array_walk()関数を使う場合
コールバック関数の実行に成功した場合はtrueが返ります
内部関数を使うにはユーザー定義関数でラップすれば良い
配列を直接操作する

array_walk($arr, 'callback'[, $third_argument]): bool
function callback($value, $index, $option)
{
    //
}
<?php
$fruits = array("d" => "lemon", "a" => "orange", "b" => "banana", "c" => "apple");

function testAlter(&$item1, $key, $prefix)
{
    $item1 = $prefix . ":" . $item1;
}

function testPrint($item2, $key)
{
    echo $key . ". " . $item2 . "\n";
}

echo "Before ...:\n";
array_walk($fruits, 'testPrint');

array_walk($fruits, 'testAlter', 'fruit');
echo "... and after:\n";

array_walk($fruits, 'testPrint')

実行結果は以下のとおり

Before ...:
d. lemon
a. orange
b. banana
c. apple
... and after:
d. fruit: lemon
a. fruit: orange
b. fruit: banana
c. fruit: apple

array_map()を使う場合
コールバック関数には内部関数とユーザー定義関数のどちらも使用可能
ただし引数の数は配列の数と一緒にする必要がある
また、複数の配列を指定する場合は各配列の要素数が同じである必要がある
引数で渡した配列のキーが維持されるのは渡した配列が一つだけであるときのみ
配列を間接的に操作するので元の配列は保持される

$new_arr = array_map($callback, $arr1[, $arr...]);
<?php
function cube($n)
{
    return pow($n, 3);
}

$arr = [1, 2, 3, 4, 5];
$new_arr = array_map('cube', $arr);
print_r($new_arr);

実行結果は以下のとおりです

Array
(
    [0] => 1
    [1] => 8
    [2] => 27
    [3] => 64
    [4] => 125
)
<?php
function show_Spanish($n, $m)
{
    return "The number " . $n . " is called " . $m . " in Spanish";
}

function map_Spanish($n, $m)
{
    return [$n => $m];
}

$a = [1, 2, 3, 4, 5];
$b = ['uno', 'dos', 'tres', 'cuatro', 'cinco'];

$c = array_map('show_Spanish', $a, $b);
print_r($c);

$d = array_map('map_Spanish', $a , $b);
print_r($d);

実行結果は以下のとおりです

//$c
Array
(
    [0] => The number 1 is called uno in Spanish
    [1] => The number 2 is called dos in Spanish
    [2] => The number 3 is called tres in Spanish
    [3] => The number 4 is called cuatro in Spanish
    [4] => The number 5 is called cinco in Spanish
)

//$d
Array
(
    [0] => Array
        (
            [1] => uno
        )

    [1] => Array
        (
            [2] => dos
        )

    [2] => Array
        (
            [3] => tres
        )

    [3] => Array
        (
            [4] => cuatro
        )

    [4] => Array
        (
            [5] => cinco
        )

)

連想配列を値で並べ替える

asort()関数、arsort()関数を使う
asort()関数は連想配列の添え字と値の関連を維持したまま、値を昇順に並び替える
arsort()関数は降順に並び替える
これらの関数は与えられた配列を直接操作する
第二引数には並び替えの比較方法を指定する
SORT_NUMERICSORT_STRING
返り値はbool

<?php
$arr = ['a1' => 1, 'a2' => 2, 'a3' => 3];
arsort($arr, SORT_NUMERIC); //['a3' => 3, 'a2' => 2, 'a1' => 1]

連想配列を添え字で並び替える

ksort()関数やkrsort()関数を使う
上のasort()関数の添え字で並び替えるバージョンなので
上の説明を読み替えてください

satorunooshie
経済学を学んでいる大学三年生です PHP, Kotlinを中心に学習しています 役に立てそうな英語の記事や詰まったところを共有していきます
https://satorunooshie.net
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away