php: combine multiple arrays value into one array preserving keys - php

I have multiple arrays structured like these:
$array1 = ["aaa" => 1, "bbb" => 1];
$array2 = ["aaa" => 12, "bbb" => 12];
$array3 = ["bbb" => 15, "ccc" => 15];
meaning:
every array has the same value for each key (eg: array1 has value "1" for every item in the array) but there are no arrays sharing the same value (eg: if array1 has value 1, then none of the other arrays has value = 1)
the arrays may or may not share the same keys
I need to combine these arrays in a way that the final result is something like this:
$result = [
"aaa" => [1,12],
"bbb" => [1,12,15],
"ccc" => [15],
];
meaning:
the final array must contain all the keys from the previous arrays
the value of the key is an array composed of all the values of the previous arrays that shared the same key
I know it's a bit messy, but I hope it is clear enough. I'm struggling to build the $result array. I tried merge, combine, intersect, but none of them seems to work. Is there a way to build the $result array without using a loop?
Thanks

Does it match your goal ?
<?php
$array1 = ["aaa" => 1, "bbb" => 1];
$array2 = ["aaa" => 12, "bbb" => 12];
$array3 = ["bbb" => 15, "ccc" => 15];
$array = array_merge_recursive($array1, $array2, $array3);
print_r($array);
?>
outputs
Array
(
[aaa] => Array
(
[0] => 1
[1] => 12
)
[bbb] => Array
(
[0] => 1
[1] => 12
[2] => 15
)
[ccc] => 15
)

Merge all of array into an mergedArray. Then use 2 foreach to set it.
<?php
$array1 = ["aaa" => 1, "bbb" => 1];
$array2 = ["aaa" => 12, "bbb" => 12];
$array3 = ["bbb" => 15, "ccc" => 15];
$mergedArray = [$array1, $array2, $array3];
$result = [];
foreach ($mergedArray as $array) {
foreach ($array as $key => $item) {
$result[$key][] = $item;
}
}
echo '<pre>';
print_r($result);
echo '</pre>';
exit;
?>
The result:
Array
(
[aaa] => Array
(
[0] => 1
[1] => 12
)
[bbb] => Array
(
[0] => 1
[1] => 12
[2] => 15
)
[ccc] => Array
(
[0] => 15
)
)

Related

Remove duplicate pair of values in an array

I have an array with the following structure:
[0] => Array
(
[venue1] => 1
[venue2] => 2
)
[1] => Array
(
[venue1] => 3
[venue2] => 4
)
[2] => Array
(
[venue1] => 2
[venue2] => 1
)
[3] => Array
(
[venue1] => 5
[venue2] => 6
)
I need to remove the duplicate "pair of values", in this case row [0] and row [2]
I tried it with that code, but it doesn't work (and of course it's not very elegant) ;-)
foreach ( $compare_arr as $v1 )
{
$key = array_search( intval($v1[venue1]), array_column( $compare_arr, 'venue2' ) );
if ( $key <> '' ) unset($compare_arr[$key]);
}
Do you have an idea how to solve this?
Thanks a lot for your help!
Oliver
Here is an approach where an intermediate array is formed of sorted values. That you can then search for to find duplicate pairs to remove.
<?php
$venues =
array (
0 =>
array (
'venue1' => 1,
'venue2' => 2,
),
1 =>
array (
'venue1' => 3,
'venue2' => 4,
),
2 =>
array (
'venue1' => 2,
'venue2' => 1,
),
3 =>
array (
'venue1' => 5,
'venue2' => 6,
),
);
$result = $pairs = $venues;
array_walk($pairs, 'sort');
var_export($pairs);
foreach($pairs as $k => $pair) {
if(count(array_keys($pairs, $pair)) > 1) {
unset($result[$k]);
}
}
var_export($result);
Output:
array (
0 =>
array (
0 => 1,
1 => 2,
),
1 =>
array (
0 => 3,
1 => 4,
),
2 =>
array (
0 => 1,
1 => 2,
),
3 =>
array (
0 => 5,
1 => 6,
),
)array (
1 =>
array (
'venue1' => 3,
'venue2' => 4,
),
3 =>
array (
'venue1' => 5,
'venue2' => 6,
),
)
If you want to remove occurring duplicates rather than pruning out duplicates altogether, you can do an array_unique on the sorted array above and then use the remaining keys to filter the original array.
$tmp = $venues;
array_walk($tmp, 'sort');
$tmp = array_unique($tmp, SORT_REGULAR);
$result = array_intersect_key($venues, $tmp);
var_export($result);
Output:
array (
0 =>
array (
'venue1' => 1,
'venue2' => 2,
),
1 =>
array (
'venue1' => 3,
'venue2' => 4,
),
3 =>
array (
'venue1' => 5,
'venue2' => 6,
),
)
You might also first loop the array creating a compound key based on the ordered keys.
Then you can filter the result only keeping arrays where the count is 2 as nothing is added because there are no duplicates.
For example
$result = [];
$compare_arr = [
["venue1" => 1, "venue2" => 2],
["venue1" => 3, "venue2" => 4],
["venue1" => 2, "venue2" => 1],
["venue1" => 5, "venue2" => 6],
];
foreach ($compare_arr as $v1) {
sort($v1);
$cKey = $v1[0] .'-'. $v1[1];
if (array_key_exists($cKey, $result)) {
$result[$cKey][] = $v1;
continue;
}
$result[$cKey] = $v1;
}
$result = array_filter($result, function($item) {
return count($item) === 2;
});
print_r($result);
Output
Array
(
[3-4] => Array
(
[0] => 3
[1] => 4
)
[5-6] => Array
(
[0] => 5
[1] => 6
)
)
You can see the compound keys are the values with a - in between. If you want to have the keys numbered from 0, you can use array_values.
Php demo
Edit
If you want to keep the first matching single pair, you can check for the compound key and if it already exists continue the loop without overwriting the existing one.
$result = [];
$compare_arr = [
["venue1" => 1, "venue2" => 2],
["venue1" => 3, "venue2" => 4],
["venue1" => 2, "venue2" => 1],
["venue1" => 5, "venue2" => 6]
];
foreach ($compare_arr as $v1) {
sort($v1);
$cKey = $v1[0] .'-'. $v1[1];
if (array_key_exists($cKey, $result)) {
continue;
}
$result[$cKey] = $v1;
}
print_r($result);
Output
Array
(
[1-2] => Array
(
[0] => 1
[1] => 2
)
[3-4] => Array
(
[0] => 3
[1] => 4
)
[5-6] => Array
(
[0] => 5
[1] => 6
)
)
Php demo
Whether you use a classic foreach() loop or functional iteration, there is no reason to iterate the input array more than once.
This snippet will appear nearly identical to TheFourthBird's answer, but I don't like the unnecessary use of continue. This snippet will ensure no that rows in the result array have 100% shared venue values (in any order). The subarray keys will also not suffer reordering; in other words the first element key will be venue1 then the second element will be venue2. Using implode() offers additional flexibility because the code won't need to be altered if the number of elements in each row changes.
$result = [];
foreach ($data as $index => $row) {
sort($row);
$key = implode('-', $row);
if (!isset($result[$key])) {
$result[$key] = $data[$index];
}
}
var_export(array_values($result));
Output:
array (
0 =>
array (
'venue1' => 1,
'venue2' => 2,
),
1 =>
array (
'venue1' => 3,
'venue2' => 4,
),
2 =>
array (
'venue1' => 5,
'venue2' => 6,
),
)
To completely remove all rows where venue values are shared, maintain a "found" array as well as a "result" array.
Code: (Demo)
$result = [];
foreach ($data as $index => $row) {
sort($row);
$key = implode('-', $row);
if (!isset($found[$key])) {
$found[$key] = true;
$result[$key] = $data[$index];
} else {
unset($result[$key]);
}
}
var_export(array_values($result));
Output:
array (
0 =>
array (
'venue1' => 3,
'venue2' => 4,
),
1 =>
array (
'venue1' => 5,
'venue2' => 6,
),
)

PHP Merge arrays and add a value

I need help merging two PHP arrays:
Array 1:
Array
(
[0] => 2
[1] => 3
[2] => 4
[3] => 6
)
Array 2:
Array
(
[0] => Array
(
[id_sabor] => 2
[chocolate] => N
)
[1] => Array
(
[id_sabor] => 3
[chocolate] => S
)
[2] => Array
(
[id_sabor] => 4
[chocolate] => N
)
[3] => Array
(
[id_sabor] => 5
[chocolate] => S
)
[4] => Array
(
[id_sabor] => 6
[chocolate] => N
)
)
The values on array 1 are the active objects. I need to keep on Array 2 or on a new array only the ones with an [id_sabor] that matches in the array 1 (in this case: 2, 3, 4 and 6). Also, on those that [chocolate]=S add a new value: [costo_extra]=25.
One way to do that could be to use array_reduce and use in_array to check if the first array contains the value of id_sabor.
$array1 = [2, 3, 4, 6];
$array2 = [
["id_sabor" => 1, "chocolate" => "N"],
["id_sabor" => 2, "chocolate" => "N"],
["id_sabor" => 3, "chocolate" => "S"],
["id_sabor" => 4, "chocolate" => "N"],
["id_sabor" => 5, "chocolate" => "S"],
["id_sabor" => 6, "chocolate" => "N"]
];
$array2 = array_reduce($array2, function($carry, $item) use ($array1){
if (in_array($item["id_sabor"], $array1)) {
if ($item["chocolate"] === "S") {
$item["costo_extra"] = 25;
}
$carry[] = $item;
}
return $carry;
});
Demo

Convert value from specific multidimensional array key into key in new array with original arrays as value

Basically I just would like to know if there is a built-in way of doing this, that might be faster, like maybe with an array_map callback or something:
function array_rekey($a, $column)
{
$array = array();
foreach($a as $keys) $array[$keys[$column]] = $keys;
return $array;
}
This should work for you:
Just pass NULL as second argument to array_column() to get the full array back as values and use $column as third argument for the keys.
$result = array_column($arr, NULL, $column);
example input/output:
$arr = [
["a" => 1, "b" => 2, "c" => 3],
["a" => 4, "b" => 5, "c" => 6],
["a" => 7, "b" => 8, "c" => 9],
];
$column = "b";
$result = array_column($arr, NULL, $column);
print_r($result);
output:
Array
(
[2] => Array
(
[a] => 1
[b] => 2
[c] => 3
)
[5] => Array
(
[a] => 4
[b] => 5
[c] => 6
)
[8] => Array
(
[a] => 7
[b] => 8
[c] => 9
)
)

Merging associate arrays in PHP

I have a serialized array stored in a cookie, at one point in my application I need to merge this array with another array with the same design, so:
Array 1:
$arr1 = array(
"user_id" => 1,
"item_id" => 2,
"quant" => 3
);
I set this in a cookie with:
serialize($arr1);
Array 2:
$arr2 = array(
"user_id" => 5,
"item_id" => 5,
"quant" => 6
);
My attempt at merging the two arrays:
First I unserialize the first array value that is in my cookie, followed by a merge with the second array
$un_arr1 = unserialize($cookie_val);
$final = array_merge($arr2, $un_arr1);
This is returning me only the values from the first array though.
What I am trying to achieve:
Array
(
[0] => Array
(
[user_id] => 1
[item_id] => 2
[quant] => 3
)
[1] => Array
(
[user_id] => 4
[item_id] => 5
[quant] => 6
)
)
$final = array($array1, $array2);
You are looking for array_merge_recursive instead of array_merge.
<?php
$A = array('a' => 1, 'b' => 2, 'c' => 3);
$B = array('c' => 4, 'd'=> 5);
$result = array_merge_recursive($A, $B);
print_r($result);
See it in action.

Merge two multidimensional arrays and reindex all subarrays

I have two arrays, I want to merge these two arrays into single array. Please view the detail below:
First Array:
Array
(
[0] => Array
(
[a] => 1
[b] => 2
[c] => 3
)
[1] => Array
(
[a] => 3
[b] => 2
[c] => 1
)
)
Second Array:
Array
(
[0] => Array
(
[d] => 4
[e] => 5
[f] => 6
)
[1] => Array
(
[d] => 6
[e] => 5
[f] => 4
)
)
I want this result. Does somebody know how to do this?
Array
(
[0] => Array
(
[0] => 1
[1] => 2
[2] => 3
)
[1] => Array
(
[0] => 3
[1] => 2
[2] => 1
)
[2] => Array
(
[0] => 4
[1] => 5
[2] => 6
)
[3] => Array
(
[0] => 6
[1] => 5
[2] => 4
)
)
Hope you have understand the question.
Thank you in advance.
Try array_merge:
$result = array_merge($array1, $array2);
FIXED (again)
function array_merge_to_indexed () {
$result = array();
foreach (func_get_args() as $arg) {
foreach ($arg as $innerArr) {
$result[] = array_values($innerArr);
}
}
return $result;
}
Accepts an unlimited number of input arrays, merges all sub arrays into one container as indexed arrays, and returns the result.
EDIT 03/2014: Improved readability and efficiency
more simple and modern way is:
$merged = $array1 + ['apple' => 10, 'orange' => 20] + ['cherry' => 12, 'grape' => 32];
new array syntax from php 5.4
If you want to return the exact result you specify in your question then something like this will work
function array_merge_no_keys() {
$result = array();
$arrays = func_get_args();
foreach( $arrays as $array ) {
if( is_array( $array ) ) {
foreach( $array as $subArray ) {
$result[] = array_values( $subArray );
}
}
}
return $result;
}
As a purely native function solution, merge the arrays, then reindex each subarray.
Code: (Demo)
$a = [
['a' => 1, 'b' => 2, 'c' => 3],
['a' => 3, 'b' => 2, 'c' => 1],
];
$b = [
['d' => 4, 'e' => 5, 'f' => 6],
['d' => 6, 'e' => 5, 'f' => 4],
];
var_export(
array_map('array_values' array_merge($a, $b))
);
Output:
array (
0 =>
array (
0 => 1,
1 => 2,
2 => 3,
),
1 =>
array (
0 => 3,
1 => 2,
2 => 1,
),
2 =>
array (
0 => 4,
1 => 5,
2 => 6,
),
3 =>
array (
0 => 6,
1 => 5,
2 => 4,
),
)

Categories