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!

Paolo_Mulder
  • 1,233
  • 1
  • 16
  • 28
  • 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());` – ourmandave May 29 '19 at 12:36
  • @ourmandave : 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 baseMap – Paolo_Mulder May 29 '19 at 12:46

4 Answers4

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();
IndianCoding
  • 2,602
  • 1
  • 6
  • 12
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);
nice_dev
  • 17,053
  • 2
  • 21
  • 35
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();
        });
Paolo_Mulder
  • 1,233
  • 1
  • 16
  • 28
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']
        ];
  });
nakov
  • 13,938
  • 12
  • 60
  • 110
  • 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. – nakov May 29 '19 at 12:31
  • Thanks for replying , yes they will be dynamic... Basemap will be set fixed as a class property . The rest will need to be dynamic... – Paolo_Mulder May 29 '19 at 12:36