Extract values from multidimensional array and store in separate array - php

I need to extract values from a multidimensional array. The startpoint is however an stdClass object. The aim is to use the extracted values to create a graph. The graph is not part of this question.
Question:
Is there a shorter and more straightforward way, then below?
Note that the values can be 100 so I do not plan to extract the values, one by one.
// Create an stdClass.
$products = (object)[
'group' => [
['level' => "12"],
['level' => "30"],
['level' => "70"],
]
];
// Transform stdClass to array.
$products = json_decode(json_encode($products), true);
var_dump($products);
// Calc amount of subarrays.
$amount_of_subarrays = count($products['group']);
$amount_of_subarrays = $amount_of_subarrays - 1; // Adjust since objects start with [0].
// Extract data from [$products], populate new array [$array].
$array = [];
for ($i=0; $i <= $amount_of_subarrays; $i++) {
$tmp = $products['group'][$i]['level'];
array_push($array, $tmp);
}
var_dump($array);
Result (as expected):
array(3) {
[0] =>
string(2) "12"
[1] =>
string(2) "30"
[2] =>
string(2) "70"
}

Simplest way I know of is to use the array_column function which returns the values from a single column in the input array
E.g. array_column($products['group'], 'level') should return the expected result.

You not need the Transform with json_encode and json_decode from stdClass to array
if use this:
$result = array_column($products->group, 'level');

Related

Cannot iterate over array after json_decode(file_get_contents(filename))

I want to write an Array as JSON into a file. Then i want to get the content, decode it and iterate over the array. The Problem is i cannot iterate over the Array that i get from the file. What am i doing wrong?
var_dump() shows the array.
<?php
$array = array(
array("Artikel" => "Bananen",
"Menge" => 10,
"id" => "4711"
),
array("Artikel" => "Eier",
"Menge" => 1,
"id" => "abc"
)
);
file_put_contents("daten.json", json_encode($array));
$array1 = json_decode(file_get_contents("daten.json"));
var_dump($array1);
for($i=0; $i<count($array1); $i++){
echo $array1[$i]["Menge"];
echo "<br>";
}
?>
If you run your code, you will get the error Cannot use object of type stdClass as array.
This is because when json_encode is executed, the nested arrays are interpreted as an objects.
If you write:
$array1 = json_decode(file_get_contents("daten.json"), true);
then the objects will be converted to arrays and everything will work as expected.

PHP only get values from multidimensional array where keys intersect with other array

I think this should be something simple, but I can't find a way to do it.
I have two arrays, one with colors and ids
$color_ids = [
'green' => [1,2,3],
'blue' => [4,5],
'red' => [6],
'pink' => [7,8,9],
'yellow' => [10]
];
and others with selection.
$select = ['green', 'red', 'yellow'];
Then I need the ids where intersects keys between $color_ids and $select. This should be the result (a simple linear array):
$results = [1,2,3,6,10];
I've tried this:
$result = array_values(array_intersect_key( $color_ids, array_flip($select ) ) );;
But I get multidimensional array:
array(3) {
[0]=> array(3) { [0]=> int(1) [1]=> int(2) [2]=> int(3) }
[1]=> array(1) { [0]=> int(6) }
[2]=> array(1) { [0]=> int(10) }
}
I get the same result with this:
$result = [];
foreach ($select as $key) {
if (isset($color_ids[$key]))
$result[] = $color_ids[$key];
}
How can I get a simple linear array with ids?
1) Iterate over the key array
2) Merge all the arrays into one using array_merge
$select = ['green', 'red', 'yellow'];
$finalArray=[];
foreach($select as $value){
$finalArray= array_merge($finalArray,$color_ids[$value]);
}
echo "<pre>";
print_r($finalArray);
Output:
Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => 6
[4] => 10
)
You can use array_merge with the ... operator which is a common flattening technique demonstrated here.
array_merge(...$result);
Array Merge documentation.
Splat Operator documentation.
with foreach
$result = [];
foreach($color_ids as $color => $ids){
$result = array_merge($result, in_array($color, $select) ? $ids : []);
}
If you are looking for a fully "functional style" solution, here's one.
Set up your filtering array ($select) so that it has keys like the master array's keys. In other words, flip the values into keys.
Then swiftly filter the master array using array_intersect_key().
Then to flatten the remaining data, prepend the splat/spread operator and call array_merge().
Until you are on a php version that allows associative arrays to be spread, then you'll need to call array_values() to reindex the first level keys so that the spread operator doesn't choke.
Code: (Demo)
var_export(
array_merge(
...array_values(
array_intersect_key(
$color_ids,
array_flip($select)
)
)
)
);
Or if you prefer jumble the syntax into a single line:
var_export(array_merge(...array_values(array_intersect_key($color_ids, array_flip($select)))));
Although a foreach() may perform a few nanoseconds faster than functional programming, you are never going to notice on such small data sets. One benefit of this coding style is that you don't have to name any temporary variables to push qualifying data into. In other words you can feed this directly into a return statement inside of a function which I find to be very tidy.
Alternatively, if you don't mind generating a result variable, then iterated array_push() calls while spreading the matching nominated color_id value is pretty simple. This technique is different in that if $select contains a color that is not a key in $color_id, then php will bark at you!
Code: (Demo)
$result = [];
foreach ($select as $color) {
array_push($result, ...$color_ids[$color]);
}
var_export($result);
Both techniques offer the same result.

php strangely nested key/value array - how to transform/map to be more usable? [duplicate]

This question already has answers here:
Generate an associative array from an array of rows using one column as keys and another column as values
(3 answers)
Closed 5 months ago.
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.)?
If it looks JSONish, array_column helps. Simply:
<?php
var_export(array_column($array, 'value', 'name'));
Output:
array (
'someName1' => 'someValue1',
'someName2' => 'someValue2',
)
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
)
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.
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',
)
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"
}
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',
)
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.

Sorting an array by the values of another array

I have a some messy data coming in from a feed, and am trying to figure out how to sort it correctly. I posted a simplified example below. I'd like to sort the people array alphabetically by the Group name.
$people = array(
"category_id_1" => array (
"Mark",
"Jenny",
"Andrew"
),
"category_id_2" => array (
"John",
"Lewis",
"Andrea"
),
"category_id_3" => array (
"Hannah",
"Angie",
"Raleigh"
)
);
$categories = array(
"category_id_1" => "Group B",
"category_id_2" => "Group C",
"category_id_3" => "Group A"
);
Ideally, the end result would be
$people = array(
"category_id_3" => array ( // Group A
"Hannah",
"Angie",
"Raleigh"
),
"category_id_1" => array ( // Group B
"Mark",
"Jenny",
"Andrew"
),
"category_id_2" => array ( // Group C
"John",
"Lewis",
"Andrea"
)
);
I've been spinning my wheels for a while now, and the closest I have gotten is this uasort, which still isn't doing the trick.
uasort($people, function ($a, $b) {
return strcmp($categories[$a], $categories[$b]);
});
Thanks so much for any help.
This can be achieved in a simpler way by taking advantage of array_replace:
// Work on a copy just to be sure the rest of your code is not affected
$temp_categories = $categories;
// Sort categories by name
asort($temp_categories);
// Replace the values of the sorted array with the ones in $people
$ordered_people = array_replace($temp_categories, $people);
You want to sort $people by its keys not its values. You can use uksort for this. Additionally you need to make $categories available in your function. I prefer use for that; but you could also make it a global variable. Final code:
uksort($people, function ($a,$b) use ($categories) {
return strcmp($categories[$a], $categories[$b]);
});
Manual for uksort
use language construct. Before example 3.
I think what you need is to Asort categories and the use that sorted array in a foreach.
Asort($categories);
Foreach($categories as $key => $group){
$new[$key] =$people[$key];
}
Var_dump($new);
https://3v4l.org/kDAQW
Output:
array(3) {
["category_id_3"]=> array(3) {
[0]=> "Hannah"
[1]=> "Angie"
[2]=> "Raleigh"
}
["category_id_1"]=> array(3) {
[0]=> "Mark"
[1]=> "Jenny"
[2]=> "Andrew"
}
["category_id_2"]=>array(3) {
[0]=> "John"
[1]=> "Lewis"
[2]=> "Andrea"
}
}
Try this(tested and working):
asort($categories);
$sorted = array();
foreach ($categories as $key => $value)
$sorted[$key]=$people[$key];
A better shorter approach:(tested and working)
asort($categories);
$result = array_merge($categories,$people);
The second method takes advantage of the fact that array_merge function replace the values in the first array with those in the second one when keys are the same.
warning : The second approach will not work if the keys are numbers. Use only string keys with it. Furthermore if the categories array has entries without corresponding entries in the people array they will be copied to the result
To solve this problem we use array_replace :
asort($categories);
$result = array_replace($categories,$people);
Var_dump($result);// tested and working

PHP how to insert array into every array in an array with a loop

I have this array:
array(n){
[0]=>
array(3){
["a"]=>int(1)
["b"]=>int(2)
["c"]=>int(3)
}
...
}
and this array:
array(n){
[0]=>
array(m){
["1x"]=>string(someText)
["2x"]=>string(someText)
["3x"]=>string(someText)
....
}
...
}
I would like to combine them to:
array(n){
[0]=>
array(3){
["a"]=>int(1)
["b"]=>int(2)
["c"]=>int(3)
["x"]=>array(m){
["1m"]=>string(someText)
["2m"]=>string(someText)
["3m"]=>string(someText)
...
}
}
...
}
i've tried looking around, but haven't found a solution for that problem i have.
i'd really appreciate ,if someone could point me at solution for this issue i have.
HUGE THANKS for anyone who might help !
If I understood you correctly, you have 2 arrays: main array and a secondary array (which you want to embed).
You want to take the main array, which holds nested arrays in it, and manipulate it by merging each nested array with the secondary array.
Here is a working code:
// The main array, which we will append to
$mainArr = array(
array (
"a" => 1,
"b" => 2,
"c" => 3
),
array (
"d" => 4,
"e" => 5,
"f" => 6
)
);
// The Array we want to embed to each of the nested arrays in $mainArr
$arrayToEmbed = array(
"1x" => "Str1x",
"2x" => "Str2x",
"3x" => "Str3x"
);
// The final result array that will contain the changes
$resultArr = $mainArr;
// Loop over each nested array in $mainArr and merge with $arrayToEmbed
foreach( $mainArr as $key => $nestedArr ){
$resultArr[$key] = array_merge($nestedArr, $arrayToEmbed);
}
// Print final result
print_r($resultArr);

Categories