Edited at

Laravelのコレクションで特定の要素をkeyにする方法

More than 1 year has passed since last update.


やりたいこと

コレクションの要素をキーにする。

ただし要素からは消したい。

例えば、id, name, emailみたいな構造のデータベースのテーブルがあるとします。

ここから複数行のレコードを取得し、

下記のような感じで整形したいとします。

id1 => [name1, email1],

id2 => [name2, email2],
id3 => [name3, email3],


やり方

mapWithKeys():bookmark: で。

Laravel 5.4以降のCollectionで使用可能なメソッドです。


テスト実装

例えば下記のように

$users_raw->mapWithKeys(function ($item)

{
return [
$item['id'] => [
'name' => $item['name'],
'email' => $item['email'],
]
];
})->toArray();

テストコード


/tests/Unit/MapWithKeysTest.php

<?php

namespace Tests\Unit;

use Tests\TestCase;
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\DatabaseTransactions;

use Illuminate\Collection as Collection;
use App\User as User;

class ExampleTest extends TestCase
{
public function testMapWithKeys()
{
echo "\n",'=== ',__FUNCTION__,' ===',"\n";

// モデルファクトリーで定義したテストユーザーを作成
$users_raw = factory(User::class, 3)->make();

// DBにINSERTしていないため、手動でIDを追加
foreach ($users_raw as $key => &$user) {
$user->id = $key + 1;
}

// テストデータ表示
echo "\n",'=== TEST_D\ATA ===',"\n";
var_dump($users_raw);

// テストの実装
$users_result = $users_raw->mapWithKeys(function ($item)
{
return [
$item['id'] => [
'name' => $item['name'],
'email' => $item['email'],
]
];
})->toArray();

// テスト結果
echo "\n",'=== TEST_RESULT ===',"\n";
var_dump($users_result);

$this->assertTrue(true);
}
}




テスト結果

array(3) {

[1]=>
array(2) {
["name"]=>
string(20) "Prof. Wiley Yundt MD"
["email"]=>
string(30) "mosciski.esperanza@example.net"
}
[2]=>
array(2) {
["name"]=>
string(12) "Easter Fahey"
["email"]=>
string(29) "donnell.bahringer@example.org"
}
[3]=>
array(2) {
["name"]=>
string(20) "Camille Cummings PhD"
["email"]=>
string(19) "bobby76@example.org"
}
}


補足1

keyBy():bookmark: でもいいのでは?

            $queryBuilder = self::select(id, name, email);

return $queryBuilder->get()->keyBy('id');


結果

id1 => [id1, name1, email1],

id2 => [id2, name2, email2],
id3 => [id3, name3, email3],

$idが要素側にも入ったままになる。

keyBy() は各要素のキーを指定するメソッドであり、要素の内容には触れないため。


補足2

keyBy():bookmark: + only()では?

            $queryBuilder = self::select(id, name, email);

return $queryBuilder->get()->keyBy('id')->only(['name', 'email']);


結果

[]

ええ……どうしてこうなった……

※配列変換が再帰的に行われるからのようです。