Merge the arrays - php

I have two arrays $array and $array2. I need to merge them on behalf of common key value i.e. entry_id.
Well I need to merge them is such a way that if the entry_id of array 1 matches with the entry_id of array2, it merges. If the entry_id doesn't match that array remains as it but it should be entered in the merged array. I have tried but i didn't get the desired results. If it is possible to do this without function?
Thanks in Advance.
Here is my code
<?php
$array = array(
array(
'title' => 'mytitleeee',
'entry_id' => 1000
),
array(
'title' => 'myt',
'entry_id' => 1001
),
array(
'title' => 'mytRRRR',
'entry_id' => 1003
),
array(
'title' => 'RUKES',
'entry_id' => 1004
)
);
$array2 = array(
array(
'author_id' => 'desc1',
'entry_id' => 1000
),
array(
'author_id' => 'desc2',
'entry_id' => 1001
),
array(
'author_id' => 'desc3',
'DAY' => 'MON',
'entry_id' => 1003
),
array(
'author_id' => 'desc7',
'DAY' => 'TUE',
'entry_id' => 1012
)
);
$x = array();
foreach($array as $value => $ans){
}
foreach($array2 as $value1 => $ans1){
}
if($ans1['entry_id']!= $ans['entry_id']){
$x = ($ans1);
echo"<pre>";
print_r($x);
}

You could apply this array_reduce call to the array_merge result:
$result = array_reduce(array_merge($array, $array2), function ($acc, $el) {
$key = $el['entry_id'];
$acc[$key] = isset($acc[$key]) ? $acc[$key] + $el : $el;
return $acc;
}, []);
$result will have the following for your sample data:
array (
1000 => array (
'title' => 'mytitleeee',
'entry_id' => 1000,
'author_id' => 'desc1',
),
1001 => array (
'title' => 'myt',
'entry_id' => 1001,
'author_id' => 'desc2',
),
1003 => array (
'title' => 'mytRRRR',
'entry_id' => 1003,
'author_id' => 'desc3',
'DAY' => 'MON',
),
1004 => array (
'title' => 'RUKES',
'entry_id' => 1004,
),
1012 => array (
'author_id' => 'desc7',
'DAY' => 'TUE',
'entry_id' => 1012,
),
)
How it works
First the two arrays are merged:
array_merge($array, $array2)
This just appends the elements of the second array after those of the first.
This array is then passed to array_reduce, which calls the callback function -- given as argument -- for each element.
Furthermore, that function also gets an accumulated value ($acc), which in the first call is [] (provided as final argument to reduce). Whatever the function returns becomes the accumulated value that is passed in the second function call (for the second element), ...etc. The final returned value becomes the return value of reduce.
So in this case the accumulated value is an associative array that is keyed by entry_id. If at a certain moment that key already exists, the current value is merged with the value that is already in $acc: this merge is done with the + operator. If the entry_id of the current element is not yet in $acc it is added to it.
This if...else is implemented with the ternary operator (... ? ... : ...).
The return$accstatement ensures that the the next time this callback is called (for the next element),$acc` is again that accumulated value.

Related

Undefined offset Error when searching Array

I am searching an array for a known value wid to get the key which will then help me get the cid value.
$proximity = array(
'0' => array ('wid' => 4, 'cid' => 100),
'1' => array ('wid' => 1, 'cid' => 50),
'3' => array ('wid' => 2, 'cid' => 50)
);
$key = array_search(2, array_column($proximity, 'wid'));
print_r($key);
print_r($proximity[$key]['cid']);
When I search for wid 4 and 1 everything works great.
However when I search for wid: 2 I get Undefined offset: 2.
Why is this happening and how do I fix it?
Array_column returns values of field as usual indexed array, even if source array is associative. So the returned key is correct only when source array has no omitted indexes, and your search, in fact, gets "position" in array.
For example, for such an array
$proximity = array(
'a' => array ('wid' => 4, 'cid' => 100),
'b' => array ('wid' => 1, 'cid' => 50),
'c' => array ('wid' => 2, 'cid' => 50)
);
array_column will return
Array
(
[0] => 4
[1] => 1
[2] => 2
)
If you really want to search through array_column, to work around this problem and get item by that "position", use
print_r(array_slice($proximity, $key, 1)['cid']);
or
print_r(array_values($proximity)[$key]['cid']);
It's because when you are doing array_search() it is only searching the first level of the array, you can search like the following:
<?php
echo 'hello world';
$proximity = array(
'0' => array ('wid' => 4, 'cid' => 100),
'1' => array ('wid' => 1, 'cid' => 50),
'3' => array ('wid' => 2, 'cid' => 50)
);
foreach($proximity as $subarray){
$key = array_search(2, array_column($subarray, 'wid'));
echo print_r($key) . '<br />';
echo print_r($proximity[$key]['cid']) . '<br />';
}
?>
This searches each sub array that is in the main array, meaning it doesn't matter how many elements are in $proximity, it will search all of them.
array_column() is trashing your original keys. I don't think there is any shame in using a loop with a break. This is clean and fast and the gaps in the keys are no bother; in fact your original keys are preserved if you need them.
Code: (demo: https://3v4l.org/8XWcf )
$proximity = array(
'0' => array ('wid' => 4, 'cid' => 100),
'1' => array ('wid' => 1, 'cid' => 50),
'3' => array ('wid' => 2, 'cid' => 50)
);
$wid=2;
foreach($proximity as $i=>$a){
if($a['wid']==$wid){
echo "i=$i and cid={$a['cid']}";
break;
}
}
Output:
i=3 and cid=50
If you don't want control structures as iterators, this seems like a sensible alternative:
$wid=2;
$proximity=array_column($proximity,NULL,'wid');
if(isset($proximity[$wid])){
echo "cid={$proximity[$wid]['cid']}";
}else{
echo 'wid not found';
}
This assumes wid values are unique and uses the values as keys for the subarrays. Demo : https://3v4l.org/Ph1tH

Remove duplicate field by Max Order_id and sort by maximal

I have an array like this:
array (
0 =>
array (
'title' => 'HELLO';
'nid' => '50', //////DUPLICATE
'Order_id' => '240',
),
1 =>
array (
'title' => 'My View';
'nid' => '51',
'Order_id' => '220',
),
2 =>
array (
'title' => 'HELLO';
'nid' => '50', //////DUPLICATE
'Order_id' => '200',
),
3 =>
array (
'title' => 'Starts';
'nid' => '54',
'Order_id' => '195',
),
)
I need to remove duplicate Arrays by using Max Order_id and sort by maximal Order_id In this example.
Any help on doing this?
You can solve this by storing the data into an associative array keyed by nid values: if you do this in order of increasing Order_id you will be left with the most "recent" values per nid
If your data is in $array:
// Sort by Order_id
array_multisort(array_column($array, "Order_id"), $array);
// Keep one entry per nid
foreach ($array as $row) {
$hash[$row["nid"]] = $row;
}
// Convert back to indexed array:
$result = array_values($hash);
See it run on eval.in

Merge second array into first array where row value in first array matches row key in second array

I would like to merge the associative elements from my second array into my first array where the second array's subarray key matches a row's epg_channel_id value.
First array:
[
[
'num' => 1,
'name' => 'name 1',
'epg_channel_id' => 'ch111',
'added' => '1505435915',
],
[
'num' => 2,
'name' => 'name 2',
'epg_channel_id' => 'ch222',
'added' => '1505435915',
],
[
'num' => 3,
'name' => 'name 3',
'epg_channel_id' => 'ch333',
'added' => '1505435915',
],
[
'num' => 4,
'name' => 'name 4',
'epg_channel_id' => 'ch444',
'added' => '1505435915'
]
]
And the second array:
[
['ch000' => 'Um9jayBJbiBSaW8='],
['ch111' => 'Um9jayBJbiBSaW8='],
['ch222' => 'Um9jayBJbiBSaW8='],
['ch333' => 'Um9jayBJbiBSaW8='],
['ch444' => 'Um9jayBJbiBSaW8=']
]
Desired output (for one row):
Array
(
[0] => Array
(
[num] => 1
[name] => name 1
[epg_channel_id] => ch111
[added] => 1505435915
[ch111] => Um9jayBJbiBSaW8=
)
...
)
I tried array_recursive, array merge and not works.
If the corresponding indexes in both arrays are guaranteed to have the same channel id, this will work quite efficiently. For example, if $array1[0] is guaranteed to have the same channel id as $array2[0] this solution will work nicely:
$combined = [];
foreach($array1 as $key=>$val){
$combined[$key] = $val + $array2[$key];
}
However, if the corresponding indexes are not guaranteed to have the same channel ids, this solution will not work, and you'll need to use one of the other posted answers.
One last note if you do use this method is that if the arrays are different sizes, you will want the largest one to be $array1. So, just do a comparison to see which has the most elements.
You have to loop over two arrays to get desired result: as you have to match epg_channel_id of first array to second arrays inner key
$arr1 = Array
(
0 => Array
(
"num" => 1,
"name" => "name 1",
"epg_channel_id" => "ch111",
"added" => "1505435915",
),
1 => Array
(
"num" => 2,
"name" => "name 2",
"epg_channel_id" => "ch222",
"added" => "1505435915",
),
2 => Array
(
"num" => 3,
"name" => "name 3",
"epg_channel_id" => "ch333",
"added" => "1505435915",
),
3 => Array
(
"num" => 4,
"name" => "name 4",
"epg_channel_id" => "ch444",
"added" => "1505435915",
),
);
$arr2 = Array
(
0 => Array
(
"ch000" => "Um9jayBJbiBSaW8="
),
1 => Array
(
"ch111" => "Um9jayBJbiBSaW8="
),
2 => Array
(
"ch222" => "Um9jayBJbiBSaW8="
),
3 => Array
(
"ch333" => "Um9jayBJbiBSaW8="
),
4 => Array
(
"ch444" => "Um9jayBJbiBSaW8="
),
);
$new_array = array();
foreach($arr1 as $key=>$value)
{
foreach($arr2 as $key1=>$value1)
{
foreach($value1 as $key2=>$value2)
{
if($key2 == $value['epg_channel_id'])
{
$value[$key2]=$value2;
}
}
}
$new_array[$key]=$value;
}
print_r($new_array);
DEMO
You can key exists or not using array_key_exists in second array then add it to new array
Working Demo: https://eval.in/863359
$array = Array
(
Array
(
'num' => 1,
'name' => 'name 1',
'epg_channel_id' => 'ch111',
'added' => '1505435915',
),
Array
(
'num' => 2,
'name' => 'name 2',
'epg_channel_id' => 'ch222',
'added' => '1505435915',
),
Array
(
'num' => 3,
'name' => 'name 3',
'epg_channel_id' => 'ch333',
'added' => '1505435915',
),
Array
(
'num' => 4,
'name' => 'name 4',
'epg_channel_id' => 'ch444',
'added' => '1505435915'
)
);
$array2 = Array
(
Array
(
'ch000' => 'Um9jayBJbiBSaW8='
),
Array
(
'ch111' => 'Um9jayBJbiBSaW8='
),
Array
(
'ch222' => 'Um9jayBJbiBSaW8='
),
Array
(
'ch333' => 'Um9jayBJbiBSaW8='
),
Array
(
'ch444' => 'Um9jayBJbiBSaW8='
)
);
$newArray =[];
foreach ($array as $key => $value) {
foreach ($array2 as $key2 => $value2) {
if (array_key_exists($value['epg_channel_id'], $value2)) {
$value[$value['epg_channel_id']] = $value2[$value['epg_channel_id']];
}
}
$newArray[] = $value;
}
echo "<pre>";
print_r($newArray);
array_merge_recursive works well for associated array that have keys are string. Numeric keys will be appended. From php.net
If the input arrays have the same string keys, then the values for these keys are merged together into an array, and this is done recursively, so that if one of the values is an array itself, the function will merge it with a corresponding entry in another array too. If, however, the arrays have the same numeric key, the later value will not overwrite the original value, but will be appended.
You have to convert your array to string keys, or using one loop to merge child arrays one by one.
Try this . I hope it will solve your problems. I have tested it.
foreach ($array1 as $key => $value){
// echo $key;
foreach ($array2 as $i =>$item){
foreach ($item as $j=>$subitem){
if($value['epg_channel_id'] == $j){
$array1[$key][$j] = $subitem;
}
}
}
}
print_r($array1);
try to read the value of 'epg_channel_id' from array1
and insert it to array1 itself from getting 'ch111' from array2
$ch_name = $array1[$i]['epg_channel_id'];
$id = $array1[$i]['num'];
$ch_value = $array2[$id]['$ch_name'];
$array1[$i]["$ch_name"] = $ch_value;
try to put in foreach for every array
$new_arr = [];
foreach($arr1 as $val){
foreach($arr2 as $val2){
if(array_key_exists($val['epg_channel_id'], $val2)){
$val[$val['epg_channel_id']] = $val2[$val['epg_channel_id']];
break;
}
}
$new_arr[] = $val;
}
print_r($new_arr);
The bad news is that your second array is not suitably structured to serve as a lookup array. The good news is that the step to flatten the structure into a simple associative array is quite easy.
Once the lookup is declared, just use a loop and modify-by-reference as you use array union syntax to append the desired key-value pairs.
I do not recommend any answers that are using nested loops -- they will not perform efficiently.
Code: (Demo)
$lookup = array_merge(...$array2);
foreach ($array as &$row) {
$row += [$row['epg_channel_id'] => $lookup[$row['epg_channel_id']]];
}
var_export($array);

Appending multiple values to associative array in PHP [duplicate]

This question already has answers here:
Merge two 2d arrays by shared column value
(6 answers)
Closed last month.
I would like to create a PHP array that will end up looking like this:
idPlayer namePlayer Points
1 John 20
2 Sam 25
3 Ben 22
But I would like to append the values not all at once:
First append the idPlayer and namePlayer
Then append the points for that idPlayer (I would have a $idPlayer variable to use each time I loop)
How could I do this in PHP?
I was thinking:
$myArray['idPlayer'] = "1";
$myArray['namePlayer'] = "John";
$myArray['Points'] = "20"
And then, how would I tell the array to go to the next row?
// output array
$myArray = array();
// your loop
while (something) {
// make an array for this iteration
$itarr = array();
// put stuff in it
$itarr['idPlayer'] = "1";
$itarr['namePlayer'] = "John";
$itarr['Points'] = "20"
// append it to output array using standard array indexing
$myArray[] = $itarr;
// OR, your own index
$myArray[$itarr['idPlayer']] = $itarr;
}
I dont know why you want to achieve such thing. But consider this example:
// like player table array initial
$players = array(
array(
'idPlayer' => 1,
'namePlayer' => 'John',
),
array(
'idPlayer' => 2,
'namePlayer' => 'Sam',
),
array(
'idPlayer' => 3,
'namePlayer' => 'Ben',
),
);
// data points to be added later (like points table)
$points = array(
array(
'idPlayer' => 1,
'Points' => 20,
),
array(
'idPlayer' => 2,
'Points' => 25,
),
array(
'idPlayer' => 3,
'Points' => 22,
),
);
$myArray = array();
foreach($players as $key => $value) {
foreach($points as $index => $element) {
// if this particular id matches the record inside points table then merge
if($value['idPlayer'] == $element['idPlayer']) {
$myArray[] = array('idPlayer' => $value['idPlayer'], 'namePlayer' => $value['namePlayer'], 'Points' => $element['Points']);
}
}
}
Should output something like: (can be used in a tabular data)
Array
(
[0] => Array
(
[idPlayer] => 1
[namePlayer] => John
[Points] => 20
)
[1] => Array
(
[idPlayer] => 2
[namePlayer] => Sam
[Points] => 25
)
[2] => Array
(
[idPlayer] => 3
[namePlayer] => Ben
[Points] => 22
)
)
Use the idPlayer as index:
$players = [
1 => [
'namePlayer' => 'John',
'points' => 20,
],
5 => [
'namePlayer' => 'Seth',
'points' => 25,
],
13 => [
'namePlayer' => 'Ben',
'points' => 35,
],
];
var_dump($players);
http://codepad.viper-7.com/nSXmZF
In php <5.4 use array() instead of [] constructor.

Find all second level keys in multi-dimensional array in php

I want to generate a list of the second level of keys used. Each record does not contain all of the same keys. But I need to know what all of the keys are. array_keys() doesn't work, it only returns a list of numbers.
Essentially the output Im looking for is:
action, id, validate, Base, Ebase, Ftype, Qty, Type, Label, Unit
I have a large multi-dimensional array that follows the format:
Array
(
[0] => Array
(
[action] => A
[id] => 1
[validate] => yes
[Base] => Array
(
[id] => 2945
)
[EBase] => Array
(
[id] => 398
)
[Qty] => 1
[Type] => Array
(
[id] => 12027
)
[Label] => asfhjaflksdkfhalsdfasdfasdf
[Unit] => asdfas
)
[1] => Array
(
[action] => A
[id] => 2
[validate] => yes
[Base] => Array
(
[id] => 1986
)
[FType] => Array
(
[id] => 6
)
[Qty] => 1
[Type] => Array
(
[id] => 13835
)
[Label] => asdssdasasdf
[Unit] => asdger
)
)
Thanks for the help!
<?php
// Gets a list of all the 2nd-level keys in the array
function getL2Keys($array)
{
$result = array();
foreach($array as $sub) {
$result = array_merge($result, $sub);
}
return array_keys($result);
}
?>
edit: removed superfluous array_reverse() function
array_keys(call_user_func_array('array_merge', $a));
Merge all values and retrieve the resulting keys.
One liner:
$keys=array_unique(array_reduce(array_map('array_keys',$data),'array_merge',[]));
Or in a function:
function get_array_children_keys($data) {
return array_unique(
array_reduce(array_map('array_keys', $data), 'array_merge', [])
);
}
Now lets break this down with an example, here is some sample data:
[
['key1' => 0],
['key1' => 0, 'key2' => 0],
['key3' => 0]
]
Starting with the inner most function, we run array_map with the array_keys function:
array_map('array_keys', $data)
This gives us the keys of from all child arrays
[
['key1'],
['key1', 'key2'],
['key3']
]
Then we run the array_reduce on the data with the array_merge callback and an empty array as the initial value:
array_reduce(..., 'array_merge', []);
This converts our multiple arrays into 1 flat array:
[
'key1',
'key1',
'key2',
'key3'
]
Now we strip out our duplicates with array_unique:
array_unique(...)
And end up with all our keys:
[
'key1',
'key2',
'key3'
]
foreach($bigArray as $array){
foreach($array as $key=>$value){
echo $key;
}
}
That should do what you want.
What about something like this :
$your_keys = array_keys($your_array[0]);
Of course, this is considering all sub-arrays have the same keys ; in this case, you only need the keys of the first sub-array (no need to iterate over all first-level sub-arrays, I guess)
And, as a shortened / simplified example :
$your_array = array(
array(
'action' => 'A',
'id' => 1,
'base' => array('id' => 145),
),
array(
'action' => 'B',
'id' => 2,
'base' => array('id' => 145),
),
array(
'action' => 'C',
'id' => 3,
'base' => array('id' => 145),
)
);
$your_keys = array_keys($your_array[0]);
var_dump($your_keys);
Will get you :
array
0 => string 'action' (length=6)
1 => string 'id' (length=2)
2 => string 'base' (length=4)
You can the use implode to get the string you asked for :
echo implode(', ', $your_keys);
will get you :
action, id, base
ie, the list of the keys of the first sub-array.
function __getAll2Keys($array_val){
$result = array();
$firstKeys = array_keys($array_val);
for($i=0;$i<count($firstKeys);$i++){
$key = $firstKeys[$i];
$result = array_merge($result,array_keys($array_val[$key]));
}
return $result;
}
try this function. It will return as you want.
While #raise answers provides a shortcut, it fails with numeric keys. The following should resolve this:
$secondKeys=array_unique(call_user_func_array('array_merge', array_map('array_keys',$a)));
array_map('array_keys',$a) : Loop through while getting the keys
...'array_merge'... : Merge the keys array
array_unique(... : (optional) Get unique keys.
I hope it helps someone.
UPDATE:
Alternatively you can use
$secondKeys=array_unique(array_merge(...array_map('array_keys', $a)));
That provides same answer as above, and much faster.
My proposal, similar to this answer but faster and using spread operator (PHP 5.6+).
array_merge(...array_values($fields))
if you want move names to array values and reset keys to 0..n just use array_keys in last step.
array_keys(array_merge(...array_values($fields)))
Maybe you can use array_map function, which allows you to avoid array iteration and return an array with the keys you need as values.
will be like this
$newArray = array_map(function($value){return array_keys($value);},$yourArray);
var_dump($newArray);
array (size=2)
0 =>
array (size=9)
0 => string 'action' (length=6)
1 => string 'id' (length=2)
2 => string 'validate' (length=8)
3 => string 'Base' (length=4)
4 => string 'EBase' (length=5)
5 => string 'Qty' (length=3)
6 => string 'Type' (length=4)
7 => string 'Label' (length=5)
8 => string 'Unit' (length=4)
1 =>
array (size=9)
0 => string 'action' (length=6)
1 => string 'id' (length=2)
2 => string 'validate' (length=8)
3 => string 'Base' (length=4)
4 => string 'FType' (length=5)
5 => string 'Qty' (length=3)
6 => string 'Type' (length=4)
7 => string 'Label' (length=5)
8 => string 'Unit' (length=4)
With this function you can get all keys from a multidimensional array
function arrayKeys($array, &$keys = array()) {
foreach ($array as $key => $value) {
$keys[] = $key;
if (is_array($value)) {
$this->arrayKeys($value, $keys);
}
}
return $keys;
}
Only if all records have the same keys you could do:
$firstItem = reset($array);
$keys = array_keys($firstItem);
Obviously, this is not the correct answer to this specific question, where the records have different keys. But this might be the question you find when looking how to retrieve second level keys from an array where all keys are the same (I did). If all the record have the same keys, you can simply use the first item in the array with reset() and get the keys from the first item with array_keys().

Categories