Map array values to collection of items
Asked Answered
B

4

5

How would one do the following elegantly with laravel collections ?

Map the values of the $baseMap as keys to the collection.

The baseMap :

$baseMap = [
            'name' => 'new_name',
            'year' => 'new_year',
        ];

The collection :

 $items = collect([
            [
                'name' => 'name1',
                'year' => '1000',
                'not_in_basemap' => 'foo'
            ],
            [
                'name' => 'name2',
                'year' => '2000',
                'not_in_basemap' => 'foo'
            ],
            //...
        ]);

The end result :

$result =[
            [
                'new_name' => 'name1',
                'new_year' => '1000',

            ],
            [
                'new_name'=> 'name2',
                'new_year' => '2000',

            ],
        ];

I know how to do it in plain php , just wondering what a nice collection version would be. Thanks!

Bankston answered 29/5, 2019 at 12:16 Comment(2)
Look at the only() method. Not sure of the syntax but something like: $result = $items->only($base_map); You might have to make $base_map an array with $items->only($base_map->toArray());Parochial
@Parochial : it is a start, but it will remove only the key not_in_baseMap , it will not replace the keys in the items to the values in baseMapBankston
B
2

Thanks to @vivek_23 and @IndianCoding for giving me idea's I ended up with the following : I made a small edit to make sure the mapping and the items keys lined up. so you don't have to worry of misalignment and all in laravel collection !


$baseMap = collect($baseMap)->sortKeys();

$result = $items->map(function ($item) use ($baseMap) {

            return $baseMap->values()
                ->combine(
                    collect($item)->sortKeys()->intersectByKeys($baseMap)
                )
                ->all();
        });
Bankston answered 29/5, 2019 at 13:27 Comment(0)
E
3

I tried to find collection methods, or php functions, but without success. Some dirty code that works with different keys from both sides (items and basemap).

$result = $items->map(function($item) use ($baseMap) {
    $array = [];

    foreach($baseMap as $oldKey => $newKey){
        if(isset($item[$oldKey])){
            $array[$newKey] = $item[$oldKey];
        }
    }

    return $array;
});

$result = $result->toArray();
Enthetic answered 29/5, 2019 at 13:15 Comment(1)
Yes , I came to the same conclusion. Plain old php it prob will be. Thanks for your time mate !Bankston
B
2

Use intersectByKeys to filter your baseMap keys with $items values.

$result = $items->map(function($item,$key) use ($baseMap){
    return array_combine(array_values($baseMap),collect($item)->intersectByKeys($baseMap)->all());
});

dd($result);

Update:

In a pure collection way,

$baseMapCollect = collect($baseMap);

$result = $items->map(function($item,$key) use ($baseMapCollect){
    return $baseMapCollect->values()->combine(collect($item)->intersectByKeys($baseMapCollect->all())->values())->all();
});

dd($result);
Bindman answered 29/5, 2019 at 12:54 Comment(13)
First of you forgot the use ($baseMapCollect) in order to use the first collection in the closure, and second the result is not the expected one :)Roster
@Roster Thanks, fixed that but apparently I can't test it.Bindman
@Bankston Well, I can't test. Can you let me know what exactly do you get as output?Bindman
No worries mate, thanks for your input ! Here your results Collection {#376 ▼ #items: array:2 [▼ 0 => array:2 [▼ "name" => "new_name" "year" => "new_year" ] 1 => array:2 [▼ "name" => "new_name" "year" => "new_year" ] ] }Bankston
@Bankston I have made an update. Could you test now and let me know?Bindman
sorry , it will still output the same array .. apart from removing the "not_in_basemap" key : Collection {#374 ▼ #items: array:2 [▼ 0 => array:2 [▼ "name" => "name1" "year" => "1000" ] 1 => array:2 [▼ "name" => "name2" "year" => "2000" ] ] }Bankston
@Bankston The output seems to be same as you desired.Bindman
Look closely ... The new key should be new_name instead of name.Bankston
@Bankston Ohh.. I overlooked. I have updated my answer.Bindman
Well done mate ! Interesting approach to it. Thank youBankston
@Bankston Happy to help :) I will update you with the same once I find something more in a pure collection way.Bindman
Yes, please do !Bankston
@Bankston Updated my answer via collections strategy.Bindman
B
2

Thanks to @vivek_23 and @IndianCoding for giving me idea's I ended up with the following : I made a small edit to make sure the mapping and the items keys lined up. so you don't have to worry of misalignment and all in laravel collection !


$baseMap = collect($baseMap)->sortKeys();

$result = $items->map(function ($item) use ($baseMap) {

            return $baseMap->values()
                ->combine(
                    collect($item)->sortKeys()->intersectByKeys($baseMap)
                )
                ->all();
        });
Bankston answered 29/5, 2019 at 13:27 Comment(0)
R
0

Here are my two cents, using map. Don't know how dynamic your collection should be, but knowing the keys I would do the following:

$baseMap = [
    'name' => 'new_name',
    'year' => 'new_year',
];

$items = collect([
    [
      'name' => 'name1',
      'year' => '1000',
      'not_in_basemap' => 'foo'
    ],
    [
      'name' => 'name2',
      'year' => '2000',
      'not_in_basemap' => 'foo'
    ],

  ])->map(function($item, $key) use ($baseMap) {
        return [
             $baseMap['name'] => $item['name'],
             $baseMap['year'] => $item['year']
        ];
  });
Roster answered 29/5, 2019 at 12:28 Comment(2)
but by dynamic you mean only the content, or even the keys will change? Because this will work as long as the keys are name and year in both.Roster
Thanks for replying , yes they will be dynamic... Basemap will be set fixed as a class property . The rest will need to be dynamic...Bankston

© 2022 - 2024 — McMap. All rights reserved.