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
)
)
)
Related
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);
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;
}
});
Let's say, I have an array like this:
$array = [
'car' => [
'BMW' => 'blue',
'toyota' => 'gray'
],
'animal' => [
'cat' => 'orange',
'horse' => 'white'
]
];
Then, I want to get all the values (the colour, 'blue', 'gray', 'orange', 'white') and join them into a single array. How do I do that without using foreach twice?
Thanks in advance.
TL;DR
$result = call_user_func_array('array_merge', $array);
Credit: How to "flatten" a multi-dimensional array to simple one in PHP?
In your use case, you should use it like this:
<?php
$array = [
'car' => [
'BMW' => 'blue',
'toyota' => 'gray'
],
'animal' => [
'cat' => 'orange',
'horse' => 'white'
]
];
$result = call_user_func_array('array_merge', $array);
$result = array_values($result);
//$result = ['blue', 'gray', 'orange', 'white']
Old but as far i see not really a "working on all cases" function posted.
So here is the common classic recursively function:
function getArrayValuesRecursively(array $array)
{
$values = [];
foreach ($array as $value) {
if (is_array($value)) {
$values = array_merge($values,
getArrayValuesRecursively($value));
} else {
$values[] = $value;
}
}
return $values;
}
Example array:
$array = [
'car' => [
'BMW' => 'blue',
'toyota' => 'gray'
],
'animal' => [
'cat' => 'orange',
'horse' => 'white'
],
'foo' => [
'bar',
'baz' => [
1,
2 => [
2.1,
'deep' => [
'red'
],
2.2,
],
3,
]
],
];
Call:
echo var_export(getArrayValuesRecursively($array), true) . PHP_EOL;
Result:
// array(
// 0 => 'blue',
// 1 => 'gray',
// 2 => 'orange',
// 3 => 'white',
// 4 => 'bar',
// 5 => 1,
// 6 => 2.1,
// 7 => 'red',
// 8 => 2.2,
// 9 => 3,
// )
Try this:
function get_values($array){
foreach($array as $key => $value){
if(is_array($array[$key])){
print_r (array_values($array[$key]));
}
}
}
get_values($array);
How do I do that without using foreach twice?
First use RecursiveIteratorIterator class to flatten the multidimensional array, and then apply array_values() function to get the desired color values in a single array.
Here are the references:
RecursiveIteratorIterator class
array_values()
So your code should be like this:
$iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($array));
$flatten_array = array_values(iterator_to_array($iterator,true));
// display $flatten_array
echo "<pre>"; print_r($flatten_array);
Here's the live demo
Here's a recursive function that gives you both the ability to get an array of those endpoint values, or to get an array with all keys intact, but just flattened.
Code:
<?php
$array = [
'car' => [
'BMW' => 'blue',
'toyota' => 'gray'
],
'animal' => [
'cat' => 'orange',
'horse' => 'white'
]
];
//
print "\n<br> Array (Original): ".print_r($array,true);
print "\n<br> Array (Flattened, With Keys): ".print_r(FlattenMultiArray($array,true),true);
print "\n<br> Array (Flattened, No Keys): ".print_r(FlattenMultiArray($array,false),true);
//
function FlattenMultiArray($array,$bKeepKeys=true,$key_prefix='')
{
//
$array_flattened=Array();
//
foreach($array as $key=>$value){
//
if(Is_Array($value)){
$array_flattened=Array_Merge(
$array_flattened,
FlattenMultiArray($value,$bKeepKeys,$key)
);
}
else{
if($bKeepKeys){
$array_flattened["{$key_prefix}_{$key}"]=$value;
}
else{
$array_flattened[]=$value;
}
}
}
return $array_flattened;
}
?>
Outputs:
<br> Array (Original): Array
(
[car] => Array
(
[BMW] => blue
[toyota] => gray
)
[animal] => Array
(
[cat] => orange
[horse] => white
)
)
<br> Array (Flattened, With Keys): Array
(
[car_BMW] => blue
[car_toyota] => gray
[animal_cat] => orange
[animal_horse] => white
)
<br> Array (Flattened, No Keys): Array
(
[0] => blue
[1] => gray
[2] => orange
[3] => white
)
If you don't care about the indexes, then this should do it:
$colors = array();
foreach ($array as $item) {
$colors = array_merge($colors, array_values($item));
}
If you want to keep the indexes you could use:
$colors = array();
foreach ($array as $item) {
// this leaves you open to elements overwriting each other depending on their keys
$colors = array_merge($colors, $item);
}
I hope this helps.
what about this one?It works with ANY array depth.
private function flattenMultiArray($array)
{
$result = [];
self::flattenKeyRecursively($array, $result, '');
return $result;
}
private static function flattenKeyRecursively($array, &$result, $parentKey)
{
foreach ($array as $key => $value) {
$itemKey = ($parentKey ? $parentKey . '.' : '') . $key;
if (is_array($value)) {
self::flattenKeyRecursively($value, $result, $itemKey);
} else {
$result[$itemKey] = $value;
}
}
}
P.S. solution is not mine, but works perfectly, and I hope it will help someone.
Original source:
https://github.com/letsdrink/ouzo/blob/master/src/Ouzo/Goodies/Utilities/Arrays.php
I'm trying to add a key and value (associative) from an array to another array, where one specific key and value match. Here are the two arrays:
$array1 = array(
1 => array(
'walgreens' => 'location',
'apples' => 'product1',
'oranges' => 'product2'
),
2 => array(
'walmart' => 'location',
'apples' => 'product1',
'oranges' => 'product2',
'milk' => 'product3'
)
);
$array2 = array(
1 => array(
'walgreens' => 'location',
'apples' => 'product1',
'oranges' => 'product2',
'bananas' => 'product3',
)
);
Here is the attempt I made at modifying $array1 to have key 'bananas' and value 'product3':
$dataCJ = getCJItem($isbn);
foreach ($array1 as $subKey => $subArray) {
foreach($subArray as $dkey => $dval){
foreach($array2 as $cjk => $cjv){
foreach($cjv as $cjkey => $cjval){
if($dval['walgreens'] == $cjval['walgreens']){
$dval['bananas'] = $cjval['bananas'];
}
}
}
}
}
This doesn't work. How can I fix this?
Change => $dval to => &$dval. Currently you are creating and writing to a new variable and the update will not work in-place.
I would look at array_merge() function!
Here is a start with the PHP doc.
For your specific case, you could do the following :
foreach($array1 as $key1 => $values1){
foreach($array2 as $key2 => $values2){
if($values1[0] == $values2[0]){
$array1[$key1] = array_merge($values1, $values2);
}
}
}
Note to simplify the problem you should inverse the first key=> value pair of the array.
Having an array this way would be a lot simper :
array(
'location' => "The location (eg:walgreens)",
//...
);
This way you could change the comparison to the following instead :
$values1['location'] == $values2['location']
Which would be safer in the case the array is not built with the location as the first pair.
I have an array of items:
array(
[0] => array(
'item_no' => 1
'item_name' => 'foo
)
[1] => array(
'item_no' => 2
'item_name' => 'bar'
)
) etc. etc.
I am getting another array from a third party source and need to remove items that are not in my first array.
array(
[0] => array(
'item_no' => 1
)
[1] => array(
'item_no' => 100
) # should be removed as not in 1st array
How would I search the first array using each item in the second array like (in pseudo code):
if 'item_no' == x is in 1st array continue else remove it from 2nd array.
// Returns the item_no of an element
function get_item_no($arr) { return $arr['item_no']; }
// Arrays of the form "item_no => position in the array"
$myKeys = array_flip(array_map('get_item_no', $myArray));
$theirKeys = array_flip(array_map('get_item_no', $theirArray));
// the part of $theirKeys that has an item_no that's also in $myKeys
$validKeys = array_key_intersect($theirKeys, $myKeys);
// Array of the form "position in the array => item_no"
$validPos = array_flip($validKeys);
// The part of $theirArray that matches the positions in $validPos
$keptData = array_key_intersect($theirArray, $validPos);
// Reindex the remaining values from 0 to count() - 1
return array_values($keptData);
All of this would be easier if, instead of storing the key in the elements, you stored it as the array key (that is, you'd be using arrays of the form "item_no => item_data") :
// That's all there is to it
return array_key_intersect($theirArray, $myArray);
You can also do:
$my_array =array(
0 => array( 'item_no' => 1,'item_name' => 'foo'),
1 => array( 'item_no' => 2,'item_name' => 'bar')
);
$thrid_party_array = array(
0 => array( 'item_no' => 1),
1 => array( 'item_no' => 100),
);
$temp = array(); // create a temp array to hold just the item_no
foreach($my_array as $key => $val) {
$temp[] = $val['item_no'];
}
// now delete those entries which are not in temp array.
foreach($thrid_party_array as $key => $val) {
if(!in_array($val['item_no'],$temp)) {
unset($thrid_party_array[$key]);
}
}
Working link
If your key is not actually a key of your array but a value, you will probably need to do a linear search:
foreach ($itemsToRemove as $itemToRemove) {
foreach ($availableItems as $key => $availableItem) {
if ($itemToRemove['item_no'] === $availableItem['item_no']) {
unset($availableItems[$key]);
}
}
}
It would certainly be easier if item_no is also the key of the array items like:
$availableItems = array(
123 => array(
'item_no' => 123,
'item_name' => 'foo'
),
456 => array(
'item_no' => 456,
'item_name' => 'bar'
)
);
With this you could use a single foreach and delete the items by their keys:
foreach ($itemsToRemove as $itemToRemove) {
unset($availableItems[$itemToRemove['item_no']]);
}
You could use the following to build an mapping of item_no to your actual array keys:
$map = array();
foreach ($availableItems as $key => $availableItem) {
$map[$availableItems['item_no']] = $key;
}
Then you can use the following to use the mapping to delete the corresponding array item:
foreach ($itemsToRemove as $itemToRemove) {
unset($availableItems[$map[$itemToRemove['item_no']]]);
}