0

The Microsoft QnAMaker API is returning a JSON key/value array (Metadata) in the following format:

$array = [[
    "name" => "someName1",
    "value" => "someValue1",
],
[
    "name" => "someName2",
    "value" => "someValue2",
],
 ..etc..
];

How do i transform it to be in the following more usable format:

$array = [
    "someName1" => "someValue1",
    "someName2" => "someValue2",
    ..etc..
];

I know I can do it using a loop... Is there a way to leverage on built in functions?

If a loop is the only way, how would you write it and why (performance/readibility/etc.)?

Leo
  • 5,013
  • 1
  • 28
  • 65
  • Could you not simply store `$array[0][0]` in a temp variable and then remove the second index --> `$array[0][0]` -- then set `$array[0]` ? – Zak Oct 23 '18 at 17:47
  • @Zak - not sure what you mean... – Leo Oct 23 '18 at 17:54
  • Any reason you don't want to just use a loop? It's only like 3 lines – GrumpyCrouton Oct 23 '18 at 17:56
  • @Leo after looking at it more closely, what you are asking is a little more complicated as far as restructuring your array -- You are trying to use key **values** as key **identifiers** -- This is going to require a loop .. There's just no other way around it. – Zak Oct 23 '18 at 17:56
  • @GrumpyCrouton - loop is ok... i just wondered if there was something i could leverage on... I was hoping for someone more fluent in PHP to show me a double filter and combine solution or thereabout... – Leo Oct 23 '18 at 17:57
  • I stand corrected .. Nigel's answer appears to be correct. – Zak Oct 23 '18 at 18:02
  • 1
    Sounds like what you're thinking of is flatmap. PHP doesn't have that built-in. Other folks have created their own: https://gist.github.com/davidrjonas/8f820ab0c75534b45189eba1d1fbeb23 ... which is effectively what has been posted already. – Brian Wagner Oct 23 '18 at 18:08

7 Answers7

2

There isn't really a way besides a loop, so just loop through the array, and create a new array the way you need it.

$new_array = [];
foreach($array as $row) {
    $new_array[$row['name']] = $row['value'];
}

print_r($new_array);

There may be a few functions you can tie together to do what you want, but in general, the loop would probably be more readable and easier in overall.

GrumpyCrouton
  • 8,486
  • 7
  • 32
  • 71
2

This uses a combination of array_map() to re-map each element and then array_merge() to flatten the results...

print_r(array_merge(...array_map(function($data) 
                         { return [ $data['name'] => $data['value']]; }
                       , $array)));

It's not very elegant and would be interesting to see other ideas around this.

Which gives...

Array
(
    [someName1] => someValue1
    [someName2] => someValue2
)
Nigel Ren
  • 56,122
  • 11
  • 43
  • 55
2

As my previous answer was a dupe of GrumpyCroutons, I thought I'd rewrite with many array functions for good measure. (But don't use this, just do a simple foreach).

<?php
array_walk($array, function($v) use (&$result) {
    $result[array_shift($v)] = array_values($v)[0];
});

var_export($result);

Output:

array (
  'someName1' => 'someValue1',
  'someName2' => 'someValue2',
)
Progrock
  • 7,373
  • 1
  • 19
  • 25
  • @GrumpyCrouton et al, hold your horses, I hadn't seen any answers when posting. – Progrock Oct 23 '18 at 18:06
  • 1
    This is a good and valid answer - but I would note that [`array_walk()` may not necessarily be faster than `foreach()`](http://www.ktorides.com/2015/02/php-array_walk-vs-foreach/) (Also, since this is a good and valid answer, I gave you an upvote to balance out that downvote you got when your answer was a duplicate) – GrumpyCrouton Oct 23 '18 at 18:26
  • 1
    @GrumpyCrouton I would say valid, but not good, rather ugly. I do note that a simple foreach would be preferable and dare I say, the _pythonic_ way to do this. – Progrock Oct 24 '18 at 03:42
2

If it looks JSONish, array_column helps. Simply:

<?php
var_export(array_column($array, 'value', 'name'));

Output:

array (
    'someName1' => 'someValue1',
    'someName2' => 'someValue2',
)
Progrock
  • 7,373
  • 1
  • 19
  • 25
  • Nice solution, I didn't know you could pass 3 variables to `array_column()` like that. – GrumpyCrouton Oct 24 '18 at 14:11
  • 1
    @GrumpyCrouton I did, and yet it took more than a while to come back to me. You can get a long way with some simple constructs such as a foreach. I'm always going back to the manual for array function lookups (blushes).. – Progrock Oct 24 '18 at 15:44
1

This works:

$res = [];
array_walk($array, function(&$e) use(&$res) {
    $res[$e['name']] = $e['value'];
    unset($e); // this line adds side effects and it could be deleted
});
var_dump($res);

Output:

array(2) { 
   ["someName1"]=> string(10) "someValue1" 
   ["someName2"]=> string(10) "someValue2" 
} 
pierDipi
  • 1,388
  • 1
  • 11
  • 20
1

You can simply use array_reduce:

<?php
$output = array_reduce($array, function($a, $b) {
    $a[$b['name']] = $b['value'];

    return $a;
});

var_export($output);

Output:

array (
    'someName1' => 'someValue1',
    'someName2' => 'someValue2',
)
Progrock
  • 7,373
  • 1
  • 19
  • 25
1

While getting a shift on (a non-foreach):

<?php
$c = $array;
while($d = array_shift($c))
    $e[array_shift($d)] = array_shift($d);

var_export($e);

Output:

array (
    'someName1' => 'someValue1',
    'someName2' => 'someValue2',
)

Although it suggests in the comments in the manual that shifting is more expensive than popping. You could replace the initial assignment to $c above with an array_reverse and the while-shift with a while-pop.

However, either approach is probably lousy compared to a foreach, but here for who knows whos amusement.

Progrock
  • 7,373
  • 1
  • 19
  • 25