PHP Loop through multi-dimensional array into new array - php

I have a PHP array like this...
[level1] => Array
(
[random475item] => Array
(
[attr1] => tester1
[attr2] => tester2
[attr3] => tester3
)
[random455item] => Array
(
[attr1] => tester1
[attr2] => tester2
[attr3] => tester3
)
)
I am trying to get the values of the attr2 fields in a new array. I can specify a specific like this...
$newarray = array();
newarray [] = $array['level1']['random475item']['attr2'];
newarray [] = $array['level1']['random455item']['attr2'];
But is there a way to automate this as it could be 50 random items coming up and I don't want to have to keep adding them manually.

https://www.php.net/manual/en/function.array-column.php and the code below at
https://3v4l.org/8j3ae
<?php
$array = ['level1' => [
'item1' => [
'attr1' => 'test1',
'attr2' => 'test2',
'attr3' => 'test3'
],
'item2' => [
'attr1' => 'test4',
'attr2' => 'test5',
'attr3' => 'test6'
],
]];
$values = array_column($array['level1'], 'attr2');
var_dump($values);
creates
array(2) {
[0]=>
string(5) "test2"
[1]=>
string(5) "test5"
}

You can use array_map for that :
$array = ['level1' => [
'item1' => [
'attr1' => 'test1',
'attr2' => 'test2',
'attr3' => 'test3'
],
'item2' => [
'attr1' => 'test4',
'attr2' => 'test5',
'attr3' => 'test6'
],
]];
// parse every item
$values = array_map(function($item) {
// for each item, return the value 'attr2'
return $item['attr2'];
}, $array['level1']);
I have created a sandbox for you to try;

Use foreach statement will be solved your case
$newarray = array();
foreach($array['level1'] as $randomItemKey => $randomItemValue){
$newarray[] = $randomItemValue['attr2'];
}

If the values can occur at any point in the array, you can use array_walk_recursive() which will loop through all of the values (only leaf nodes) and you can check if it is an attr2 element and add it into an output array...
$out = [];
array_walk_recursive($array, function ($data, $key ) use (&$out) {
if ( $key == "attr2" ) {
$out[] = $data;
}
});

Related

arrays with dif keys inside 1 array

like the question says, I have 2 foreach cycles, 1 cycle iterates an array with 4 keys, and the other one an array with 3 keys, how to get this two arrays in only 1 ?
I have this
....
],
],
'Detalle' => array()
];
foreach ($datos["line_items"] as $line => $item) {
$tempArray = array(
'NmbItem' => $item['name'],
'QtyItem' => $item['quantity'],
'PrcItem' => $item['price'],
'IndExe' => 1
);
}
foreach($datos["fee_lines"] as $line => $fee){
$tempArray=array(
'NmbItem' => $fee['name'],
'QtyItem' => 1,
'PrcItem' => $fee['total']
);
}
$dte['Detalle'][] = $tempArray;
}
if you notice the second array cycle doesnt contain 'indexe' key, after asign this tempArray in $dte['Detalle'][] = $tempArray only works with the last cycle, or the first one if I remove the second.
the output should be something like:
temp = Array (
array[0]
'NmbItem => name',
'QtyItem'=> 10,
'PrcItem'= 1000,
'IndExe' => 1
array[1]
'NmbItem => another name',
'QtyItem'=> 5,
'PrcItem'=> 3000
)
To make it work with your code, you should also add $dte['Detalle'][] = $tempArray; after the first loop.
The issue is that you are setting the $tempArray in each foreach so you end up with only the last one when assigning it in the $dte['Detalle'].
So, something like this should work:
foreach ($datos["line_items"] as $line => $item) {
$tempArray = array(
'NmbItem' => $item['name'],
'QtyItem' => $item['quantity'],
'PrcItem' => $item['price'],
'IndExe' => 1
);
}
$dte['Detalle'][] = $tempArray;
foreach($datos["fee_lines"] as $line => $fee){
$tempArray=array(
'NmbItem' => $fee['name'],
'QtyItem' => 1,
'PrcItem' => $fee['total']
);
}
$dte['Detalle'][] = $tempArray;
However, I would do it using the array_map function.
Docs for array_map
You can have it something like this:
<?php
$data_1 = array_map(function($item){
return array(
'NmbItem' => $item['name'],
'QtyItem' => $item['quantity'],
'PrcItem' => $item['price'],
'IndExe' => 1
);
}, $datos["line_items"]);
$data_2 = array_map(function($fee){
return array(
'NmbItem' => $fee['name'],
'QtyItem' => 1,
'PrcItem' => $fee['total']
)
}, $datos["fee_lines"]);
$dte['Detalle'] = array_merge($dte['Detalle'], $data_1, $data_2);

get an array element where another element is known?

Array
(
[0] => Array
(
[what] => b4
[map] => 74,76,77,83
)
[1] => Array
(
[what] => b2
[map] => 53,82
)
[2] => Array
(
[what] => b1
[map] => 36
)
)
abc('b4');
function abc($what){
$map = // element `map` where `what` = $what;
}
So I need to get map where what is equal to $what;
For example - if $what is b4 result should be 74,76,77,83; and so on.
How can I do this?
If you are going to access the data on a regular basis and the what is unique, then use array_column() with the third parameter as the column to use as the key. Then your array is easily access with what and no loops are harmed in this answer...
$array = Array
(
Array
(
"what" => "b4",
"map" => "74,76,77,83"
),
Array
(
"what" => "b2",
"map" => "53,82"
),
Array
(
"what" => "b1",
"map" => "36"
)
);
$array = array_column($array, null, "what");
echo $array['b4']['map'];
gives...
74,76,77,83
With array_search() and array_column() you can get the matching $map in one line:
<?php
$array = Array
(
Array
(
"what" => "b4",
"map" => "74,76,77,83"
),
Array
(
"what" => "b2",
"map" => "53,82"
),
Array
(
"what" => "b1",
"map" => "36"
)
);
function abc($array, $what) {
return $array[array_search($what, array_column($array, 'what'))]['map'];
}
echo abc($array, "b4");
The function de-constructed and explained:
function abc($array /* the complete input array */, $what /* the search string */) {
// get the key of the sub-array that has $what in column 'what':
$key = array_search($what, array_column($array, 'what'));
// use that key to get 'map' on index $key
return $array[$key]['map'];
}
A working fiddle can be found here: https://3v4l.org/0NpcX
I think "walking" through an array is easy to read and understand:
<?php
$map = [
[
'what' => "b4",
'map' => "74,76,77,83"
],
[
'what' => "b2",
'map' => "53,82"
],
[
'what' => "b1",
'map' => "36"
]
];
function lookupWhatInMap(&$map, $what) {
array_walk($map, function($entry, $key) use ($what) {
if ($entry['what'] == $what) {
print_r($entry['map']);
}
});
}
lookupWhatInMap($map, "b4");
All you have to do is loop through your map and compare values.
function abc($what){
$map = [...];
foreach($map as $item) {
if (isset($item[$what]) ) {
return $item["map"];
}
}
return false;
}
If you just want 1 value from the array, you could use a foreach and a return statement where there is a match:
$a = [
[
"what" => "b4",
"map" => "74,76,77,83"
],
[
"what" => "b2",
"map" => "53,82"
],
[
"what" => "b1",
"map" => "36"
]
];
function abc($what, $arrays)
{
foreach ($arrays as $array) {
if ($array['what'] === $what) {
return $array['map'];
}
}
return false;
}
echo(abc('b4', $a)); // 74,76,77,83
Demo
https://ideone.com/V9WNNx
$arr[] = [
'what' => 'b4',
'map' => '74,76,77,83'
];
$arr[] = [
'what' => 'b2',
'map' => '53,82'
];
$arr[] = [
'what' => 'b1',
'map' => '36'
];
echo abc('b4', $arr);
function abc($what, $arr){
$map = null;
$idx = array_search($what, array_column($arr, 'what'));
if ($idx !== false) {
$map = $arr[$idx]['map'];
}
return $map;
}

Array manipulation (compare) by specific algortihm

I have 2 array and i need compare these arrays by my specific algorithm.
Firstly, my arrays:
$old = [
'pencil' => 'red',
'eraser' => 'green',
'bag' => 'blue'
];
$new = [
'pencil' => '',
'eraser' => '',
'computer' => 'mac',
'bag' => '',
'activity' => [
'jumping',
'pool',
'reading'
]
];
Then, I wanna get this output:
$output = [
'pencil' => 'red', // old value
'eraser' => 'green', // old value
'bag' => 'blue', // old value
'computer' => 'mac', // new key & values
'activity' => [ // new key & values
'jumping',
'pool',
'reading'
]
];
So, elements (array item) in both old and new arrays will be added to the output but values should come from the old array.
The elements (array item) in the new array should be transferred to output exactly.
I wanna support my question with a photo attachment ( the sequence on the photo may not match the sequence on the my arrays ($old, $new) ):
photo
Use array_merge in order to merge element of two array:
$result = array_merge($new, $old);
The values from the second array ($old) will be merged on the first array so if you have a key in both array, the second one will be presented in the result.
I think the following code can achieve what you are looking for:
$output = []
foreach($old as $key => $value){
$output[$key] = $value;
}
foreach($new as $key => $value){
if(!array_key_exists($key, $output)){
$output[$key] = $value;
}
}
Here is my solution,
$old = [
'pencil' => 'red',
'eraser' => 'green',
'bag' => 'blue'
];
$new = [
'pencil' => '',
'eraser' => '',
'computer' => 'mac',
'bag' => '',
'activity' => [
'jumping',
'pool',
'reading'
]
];
$output = [];
foreach ($new as $newkey => $newvalue) {
if($newvalue!=""){
$output = [$old+$new];
}
}
echo "<pre>";
print_r($output);
echo "</pre>";
exit;
Here output look like,
Array
(
[0] => Array
(
[pencil] => red
[eraser] => green
[bag] => blue
[computer] => mac
[activity] => Array
(
[0] => jumping
[1] => pool
[2] => reading
)
)
)

Remove duplicates from a multidimensional array based on multiple keys

Sorry if this was asked before, but I searched a lot and couldn't find a solution.
I've been trying to solve this problem for a while now, and couldn't write the function for it.
I have an array like that:
$numbers = array(
array("tag" => "developer", "group" => "grp_1", "num" => "123123"),
array("tag" => "developer", "group" => "grp_2", "num" => "111111"),
array("tag" => "student", "group" => "grp_1", "num" => "123123"),
array("tag" => "student", "group" => "grp_2", "num" => "123123"),
array("tag" => "developer", "group" => "grp_3", "num" => "111111"),
);
I need to write a function, that removes the duplicates off this array, based on multiple keys, so my function call should look something like that:
unique_by_keys($numbers, array("num","group"));
In other terms, one number can't be in the same group more than once.
After calling unique_by_keys() by array should be like that:
$numbers = array(
array("tag" => "developer", "group" => "grp_1", "num" => "123123"),
array("tag" => "developer", "group" => "grp_2", "num" => "111111"),
array("tag" => "student", "group" => "grp_2", "num" => "123123"),
array("tag" => "developer", "group" => "grp_3", "num" => "111111"),
);
I'd appreciate if you could help me find a solution, or lead me to the correct way of thinking.
Thanks!
SOLUTION:
I was able to find a solution, by writing the following function:
( I wrote it in a way that accepts many forms of $haystack arrays )
function unique_by_keys($haystack = array(), $needles = array()) {
if (!empty($haystack) && !empty($needles)) {
$_result = array();
$result = array();
$i = 0;
foreach ($haystack as $arrayObj) {
if (is_array($arrayObj)) {
$searchArray = array();
foreach ($needles as $needle) {
if (isset($arrayObj[$needle])) {
$searchArray[$needle] = $arrayObj[$needle];
}
}
if (!in_array($searchArray, $_result)) {
foreach ($arrayObj as $key => $value) {
if (in_array($key, $needles)) {
$_result[$i][$key] = $value;
}
}
$result[] = array_merge($_result[$i], $arrayObj);
}
} else {
$result[] = $arrayObj;
}
$i++;
}
return $result;
}
}
Thanks for everyone that replied!
Bhaskar's approach which assigns unique keys in the loop to remove duplicates affords a very small function for this case.
Here is a previous and unnecessarily complicated version:
function unique_by_keys($haystack=array(),$needles=array()){
// reverse order of sub-arrays to preserve lower-indexed values
foreach(array_reverse($haystack) as $row){
$result[implode('',array_intersect_key($row,array_flip($needles)))]=$row; // assign unique keys
}
ksort($result); // sort the sub-arrays by their assoc. keys
return array_values($result); // replace assoc keys with indexed keys
}
This is the best/leanest solution I can come up with:
$numbers = array(
array("tag" => "developer", "group" => "grp_1", "num" => "123123"),
array("tag" => "developer", "group" => "grp_2", "num" => "111111"),
array("tag" => "student", "group" => "grp_1", "num" => "123123"),
array("tag" => "student", "group" => "grp_2", "num" => "123123"),
array("tag" => "developer", "group" => "grp_3", "num" => "111111")
);
function unique_by_keys($haystack=array(),$needles=array()){
foreach($haystack as $row){
$key=implode('',array_intersect_key($row,array_flip($needles))); // declare unique key
if(!isset($result[$key])){$result[$key]=$row;} // save row if non-duplicate
}
return array_values($result);
}
echo "<pre>";
var_export(unique_by_keys($numbers,array("group","num")));
echo "</pre>";
Output:
array (
0 =>
array (
'tag' => 'developer',
'group' => 'grp_1',
'num' => '123123',
),
1 =>
array (
'tag' => 'developer',
'group' => 'grp_2',
'num' => '111111',
),
2 =>
array (
'tag' => 'student',
'group' => 'grp_2',
'num' => '123123',
),
3 =>
array (
'tag' => 'developer',
'group' => 'grp_3',
'num' => '111111',
),
)
$newNumbers = array();
foreach($numbers as $key=>$values){
$newkey = $values['group'].'__'.$values['num'];
$newNumbers[$newkey] = $values;
}
var_dump($newNumbers)
Code might not be efficient, but i will work for you :)
$result = unique_by_keys($numbers, array("num","group"));
echo "<pre>";
print_R($result);
function unique_by_keys($numbers, $arr){
$new_array = array();
$output = array();
foreach ($numbers as $n){
if(isset($new_array[$n[$arr[1]]]) && $new_array[$n[$arr[1]]] == $n[$arr[0]]){
continue;
}else{
$new_array[$n[$arr[1]]] = $n[$arr[0]];
$output[] = $n;
}
}
return $output;
}

Flip associative array and store new values in subarrays to prevent losing duplicated values

I have a flat associative array which may contain duplicate values.
Array (
[for-juniors] => product_category
[for-men] => product_category
[coats] => product_category
[for-women] => product_category
[7-diamonds] => brand
)
I need to restructure the data to store the original values as new keys and the original keys pushed into subarrays associated with the new keys.
array(
'product_category' => array(
'for-juniors',
'for-men',
'coats',
'for-women'
),
'brand' => array(
'7-diamonds'
)
);
$grouped = array();
foreach ($input as $choice => $group) {
$grouped[$group][] = $choice;
}
var_dump($grouped);
Because within a foreach() loop, the values are declared BEFORE the keys, you can actually populate the new data structure with a body-less foreach() loop.
Code: (Demo)
$array = [
'for-juniors' => 'product_category',
'for-men' => 'product_category',
'coats' => 'product_category',
'for-women' => 'product_category',
'7-diamonds' => 'brand'
];
$grouped = [];
foreach ($array as $grouped[$group][] => $group);
var_export($grouped);
Output:
array (
'product_category' =>
array (
0 => 'for-juniors',
1 => 'for-men',
2 => 'coats',
3 => 'for-women',
),
'brand' =>
array (
0 => '7-diamonds',
),
)
This'll do:
function array_flip_safe(array $array) : array
{
return array_reduce(array_keys($array), function ($carry, $key) use (&$array) {
$carry[$array[$key]] ??= []; // PHP 7.0 - ^7.3: $carry[$array[$key]] = $carry[$array[$key]] ?? [];
$carry[$array[$key]][] = $key;
return $carry;
}, []);
}
The callback creates an empty array if the array doesn't already exist. Then it appends current iteration's $key ($value of array_keys($array)) to that array.
Here's an example for better understanding:
$businessHours = [
'mo' => '13:00 - 16:00',
'tu' => '8:00 - 12:00',
'we' => '13:00 - 16:00',
'th' => '8:00 - 12:00',
'fr' => '13:00 - 16:00',
'sa' => '',
'su' => '',
];
$flipped = array_flip_safe($businessHours);
ray($flipped); (or var_dump, var_export, etc.) outputs:
array:3 [▼
"13:00 - 16:00" => array:3 [▼
0 => "mo"
1 => "we"
2 => "fr"
]
"8:00 - 12:00" => array:2 [▼
0 => "tu"
1 => "th"
]
"" => array:2 [▼
0 => "sa"
1 => "su"
]
]
Note that the order of inner arrays' values is the same as the order of original array's keys.

Categories