Merge a 3D Array with 2D Array Based on Shared Values - php
I need to merge a three-dimensional array with a two-dimensional array based on a shared value for 'id.'
In the example below, "George Washington" has an 'id' of 1. I need to append his 'value', which is found in the second array where 'id' is also 1.
The 'id' of "John Adams" is 2, which is not found in the second array. As a result, his 'value' needs to be set to 0 (or NULL).
The final result is a three-dimension array where 'value' has been added to each item in the original array.
Array #1
Array
(
[0] => Array
(
[0] => Array
(
[id] => 1
[name] => "George Washington"
)
[total] => 8
[average] => 2.5
)
[1] => Array
(
[0] => Array
(
[id] => 2
[name] => "John Adams"
)
[total] => 6
[average] => 3.0
)
[2] => Array
(
[0] => Array
(
[id] => 5
[name] => "James Monroe"
)
[total] => 9
[average] => 2.0
)
)
Array #2
Array
(
[0] => Array
(
[id] => 1
[value] => 12
)
[1] => Array
(
[id] => 5
[value] => 18
)
)
Desired Result:
Array
(
[0] => Array
(
[0] => Array
(
[id] => 1
[name] => "George Washington"
)
[total] => 8
[average] => 2.5
[value] => 12
)
[1] => Array
(
[0] => Array
(
[id] => 2
[name] => "John Adams"
)
[total] => 6
[average] => 3.0
[value] => 0
)
[2] => Array
(
[0] => Array
(
[id] => 5
[name] => "James Monroe"
)
[total] => 9
[average] => 2.0
[value] => 18
)
)
What I've tried so far:
I separated all of the 'id' values from the first array into a new array named $ids. Then while looping through the items in the second array, I check to see whether the 'id' from the second array is found in the $ids array.
But then I'm stuck because I don't know how to specify which item in the first array needs to receive the new 'value'. Also, this seems like a messy solution because of the overhead involved in creating the $ids array.
Didn't even realize you had tried to list the IDs and such before I was done writing this, but here you go anyway. Good luck!
$array1_size = count($array1);
$array2_size = count($array2);
// Creates a list containing all available IDs of Array1
for ($i = 0; $i < $array1_size; $i ++) {
$id_list[] = $array1[$i][0]['id'];
$array1[$i]['value'] = NULL; // Adds a NULL to all value fields
}
// Loops through Array2
for ($i = 0; $i < $array2_size; $i++) {
if (in_array($array2[$i]['id'], $id_list)) { // Checks if each ID exists in the ID list
$key = array_search($array2[$i]['id'], $id_list); // Gets the key of the matching ID
$array1[$key]['value'] = $array2[$i]['value']; // Adds the value
}
}
Edit: Values are now set to NULL by default and thus only gets changed later on if needed.
Related
how to add array value at specfic index in php codenighter
I have array value like this Array ( [0] => Array ( [channel] => 15 [id] => clsrnMdVKq2omEuQabSCHp83ezAX6w ) [1] => Array ( [channel] => 16 [id] => MfSoHUKjD5n90EZbstpiRGY7e8cgh2 ) [2] => Array ( [channel] => 17 [id] => MfSoHUKjD5n90EZbstpiRGY7e8cgh2 ) ) Now i want to add another array value in specific index .lets say i wants to add this array value at index 1 [1] => Array ( [channel] => 20 [id] => xxxxxxxxxxxewqeqwexxxxxxxewrewrw ) Now the result output should be like this Array ( [0] => Array ( [channel] => 15 [id] => clsrnMdVKq2omEuQabSCHp83ezAX6w ) [1] => Array ( [channel] => 20 [id] => xxxxxxxxxxxewqeqwexxxxxxxewrewrw ) [2] => Array ( [channel] => 16 [id] => MfSoHUKjD5n90EZbstpiRGY7e8cgh2 ) [3] => Array ( [channel] => 17 [id] => MfSoHUKjD5n90EZbstpiRGY7e8cgh2 ) ) this is my foreach loop to serlize channel and id foreach ($channel as $key => $ch) { $user_hash['channel'] = json_encode($ch); $user_hash['id'] = random_string('alnum', 30); array_push($user_hash_array, $user_hash); }
You need to split the array into 2, then insert your new value at the end of the first sub-array, then merge it with the second sub-array. EG: an array which looks like [1,3,4,5] and you want to insert "2" at position 2, then you split at position one to have [1] and [3,4,5]; then you append "2" at the end of first sub-array to form [1,2], then merge this new subarray with the other sub-array([3,4,5]) to form [1,2] + [3,4,5]. For your implementation, try this code: $array = array() // the original array you want to modify $insert = array() // the array you want to push into the original one above $position = 1 // the position at which you want to insert the new item $newArray = array_slice($array, 0, $position, TRUE) + $insert + array_slice($array, $position, NULL, TRUE);
you can use array_splice array method for add element in array at particular position <?php $original_array = array( array("channel"=>15,"id"=>"sdfdfsf1"), array("channel"=>16,"id"=>"sdfdfsf2"), array("channel"=>17,"id"=>"sdfdfsf3") ); echo "<pre>";print_r($original_array); $inserted_element = array(array("channel"=>20,"id"=>"xxxxxxxxxxewqeqwexxxxxxxewrewrw")); $position=1; array_splice( $original_array, $position, 0, $inserted_element ); echo "<pre>";print_r($original_array); ?> Output will be as following Array ( [0] => Array ( [channel] => 15 [id] => sdfdfsf1 ) [1] => Array ( [channel] => 16 [id] => sdfdfsf2 ) [2] => Array ( [channel] => 17 [id] => sdfdfsf3 ) ) Array ( [0] => Array ( [channel] => 15 [id] => sdfdfsf1 ) [1] => Array ( [channel] => 20 [id] => xxxxxxxxxxewqeqwexxxxxxxewrewrw ) [2] => Array ( [channel] => 16 [id] => sdfdfsf2 ) [3] => Array ( [channel] => 17 [id] => sdfdfsf3 ) )
How to remove duplicate values from a multi dimensional array for specific key in php [duplicate]
This question already has answers here: How to remove duplicate values from a multi-dimensional array in PHP (18 answers) Closed 2 years ago. I searched for solutions on here but didn't find one for my use case. I have a big array which is built like this example: Array ( [0] => Array ( [Template] => page.html5 ) [1] => Array ( [Template] => page2.html5 ) [2] => Array ( [Template] => page.html5 ) [3] => Array ( [Template] => page2.html5 ) [4] => Array ( [Template] => page.html5 ) [5] => Array ( [Template] => page2.html5 ) [6] => Array ( [id] => 27 [table] => tl_custom [type] => text [data] => Array ( [fragment] => example [previewId] => 1 [isActive] => 1 ) ) ) I would like to remove all duplicate values for the array key "Template", but besides that I want the array to stay the way it is. So afterwards my Array should look like: Array ( [0] => Array ( [Template] => page.html5 ) [1] => Array ( [Template] => page2.html5 ) [6] => Array ( [id] => 27 [table] => tl_custom [type] => text [data] => Array ( [fragment] => example [previewId] => 1 [isActive] => 1 ) ) ) Is there a way to achieve this without using lots of memory? Thanks for your answers :)
You could use the following logic, which uses: array_map() to flatten the array with index keys-values, and serialize() (stringify) the last array element so we can use array_unique() on the result. Then, to restore the stringified array, i.e. turn it back into an array, we use unserialize(). <?php $newArr = array_unique(array_map(function ($el) { return $el['Template'] ?? serialize($el); }, $arr)); // restore the last element to array $last = array_key_last($newArr); // (PHP 7 >= 7.3.0)* $newArr[$last] = unserialize($newArr[$last]); *if PHP version <7.3.0 use: end($newArr); $last = key($newArr); Output: Array ( [0] => page.html5 [1] => page2.html5 [6] => Array ( [id] => 27 [table] => tl_custom [type] => text [data] => Array ( [fragment] => example [previewId] => 1 [isActive] => 1 ) ) ) working demo
The code below loops the array, marks indexes for removal and then another loop does the removals: $templates = array(); //This will store the remove plan for ($index = 0; $index < count($input); $index++) { if (isset($input[$index]["Template"])) { //Ignore items where there is no template if (isset($templates[$input[$index]["Template"]])) { //Let's check whether we have already seen this template $templates[$input[$index]["Template"]] = array(); //From now on we will find duplicates for this dude } else { //Mark for removal $templates[$input[$index]["Template"]][]=$index; } } } //Actual removals foreach($templates => $index) { //Removing the actual element: unset($input[$index]["Template"]); //Remove the parent as well if it becomes empty if (!count($input[$index])) unset($input[$index]); } The memory need for this algorithm is: average(element_size) * number_of_elements
Find if two different keys have the same value in 2 arrays PHP
My arrays are: Array1 ( [0] => Array ( [id] => 2 [name] => Melamine [deleted] => 0 ) [1] => Array ( [id] => 4 [name] => Vinyl [deleted] => 0 ) [2] => Array ( [id] => 5 [name] => Polyu [deleted] => 0 ) ) Array2 ( [0] => Array ( [productFinish] => 29 [type] => 2 ) [1] => Array ( [productFinish] => 29 [type] => 4 ) ) So, i would like to return first array if id of 1st array matches with type of another array. In this case, first 2 indexes of first array must come out in return. Thanks
You can use array_uintersect to get the results you want, supplying a callback function that compares the id value in array1 with the type value in array2: $result = array_uintersect($array1, $array2, function ($a1, $a2) { return ($a1['id'] ?? $a1['type']) - ($a2['type'] ?? $a2['id']); }); print_r($result); Note that because the callback is also called with values exclusively from $array1 or $array2 (for sorting), we have to allow for that in the comparison expression. Output: Array ( [0] => Array ( [id] => 2 [name] => Melamine [deleted] => 0 ) [1] => Array ( [id] => 4 [name] => Vinyl [deleted] => 0 ) ) Demo on 3v4l.org
Ok, i got it with for loop. $newTypeFilter = []; for($i=0; $i < count($arra1); $i++){ for($j=0;$j<count($arra2); $j++){ if($arra1[$i]['id'] == $arra2[$j]['type']){ $newTypeFilter[] = $arra1[$i]; } } } Any other answers will be appreciated. Thanks
Sorting multiple subarrays based on a total count from all sub arrays
I have some data which looks like this (reduced) Array ( [datasets] => Array ( [0] => Array ( [label] => NEW [backgroundColor] => #37fdfd [data] => Array ( [0] => 0 [1] => 0 [2] => 5 [3] => 0 ) ) [1] => Array ( [label] => Grade A [backgroundColor] => #76ef76 [data] => Array ( [0] => 8 [1] => 12 [2] => 11 [3] => 0 ) ) [2] => Array ( [label] => Grade B [backgroundColor] => #f9f96d [data] => Array ( [0] => 1 [1] => 6 [2] => 5 [3] => 3 ) ) [3] => Array ( [label] => Grade C [backgroundColor] => #f3ca36 [data] => Array ( [0] => 3 [1] => 0 [2] => 1 [3] => 4 ) ) [4] => Array ( [label] => Grade D [backgroundColor] => #f3ca36 [data] => Array ( [0] => 3 [1] => 0 [2] => 1 [3] => 0 ) ) ) [labels] => Array ( [0] => User 0 [1] => User 1 [2] => User 2 [3] => User 3 ) ) Here is a JSON string of the data (not reduced, numbers may differ slightly) {"datasets":[{"label":"NEW","backgroundColor":"#37fdfd","data":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]},{"label":"Grade A","backgroundColor":"#76ef76","data":[9,14,12,0,4,17,13,0,10,0,18,18,12,13,13,4]},{"label":"Grade B","backgroundColor":"#f9f96d","data":[1,6,5,0,6,5,2,0,1,0,2,1,4,3,1,15]},{"label":"Grade C","backgroundColor":"#f3ca36","data":[3,0,1,0,2,0,0,0,0,0,1,1,0,0,0,0]},{"label":"Grade C","backgroundColor":"#f3ca36","data":[3,0,1,0,2,0,0,0,0,0,1,1,0,0,0,0]}],"labels":["User 0","User 1","User 2","User 3","User 4","User 5","User 6","User 7","User 8","User 9","User 10","User 11","User 12","User 13","User 14","User 15"]} Each dataset has an array of data which has keys that directly relates to a key in the labels array. This is currently sorted in alphabetical order by the label. This data structure is the structure required for Chart.js, which I am using to display a stacked bar chart on my webpage. Essentially what I need to accomplish is to sort the data array for every user in the labels array based on the sum of each data set for that user. I also need to sort the labels array to be in the same order. My original idea on how to achieve this is to create a temporary array, loop through all the data sets and add them to this temporary array in the order necessary, but I got stuck after calculating the total for each user. Here is my attempt: $return = []; foreach($calculated['labels'] as $key => &$name) { $total = 0; foreach($calculated['datasets'] as $dataset) { $total += $dataset['data'][$key]; } echo "$name - $total<br>"; } How can I sort my data and labels in descending order based on the total for each user from all datasets. Here is my expected output for the reduced data above Array ( [datasets] => Array ( [0] => Array ( [label] => NEW [backgroundColor] => #37fdfd [data] => Array ( [2] => 5 [1] => 0 [0] => 0 [3] => 0 ) ) [1] => Array ( [label] => Grade A [backgroundColor] => #76ef76 [data] => Array ( [2] => 11 [1] => 12 [0] => 8 [3] => 0 ) ) [2] => Array ( [label] => Grade B [backgroundColor] => #f9f96d [data] => Array ( [2] => 5 [1] => 6 [0] => 1 [3] => 3 ) ) [3] => Array ( [label] => Grade C [backgroundColor] => #f3ca36 [data] => Array ( [2] => 1 [1] => 0 [0] => 3 [3] => 4 ) ) [4] => Array ( [label] => Grade D [backgroundColor] => #f3ca36 [data] => Array ( [2] => 1 [1] => 0 [0] => 3 [3] => 0 ) ) ) [labels] => Array ( [2] => User 2 //23 total across all data sets [1] => User 1 //18 total across all data sets [0] => User 0 //15 total across all data sets [3] => User 3 //7 total across all data sets ) ) The key in the labels array acts as a unique identifier for each user in each dataset data array. Notice how each set of data inside of each dataset is in the same order, as is the labels array. Each set should be ordered by the total amount from all sets for each user, not necessarily the highest number in each dataset. For clarification, each set of data in each dataset contains a list of values, the key for each value is directly related to the key for each user in the labels array. So in my example, we have User 0 who has the key "0". This user has a total of 23 from adding up the values from each dataset with the key "0".
Complete solution: // get array $a = json_decode('{"datasets":[{"label":"NEW","backgroundColor":"#37fdfd","data":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]},{"label":"Grade A","backgroundColor":"#76ef76","data":[9,14,12,0,4,17,13,0,10,0,18,18,12,13,13,4]},{"label":"Grade B","backgroundColor":"#f9f96d","data":[1,6,5,0,6,5,2,0,1,0,2,1,4,3,1,15]},{"label":"Grade C","backgroundColor":"#f3ca36","data":[3,0,1,0,2,0,0,0,0,0,1,1,0,0,0,0]},{"label":"Grade C","backgroundColor":"#f3ca36","data":[3,0,1,0,2,0,0,0,0,0,1,1,0,0,0,0]}],"labels":["User 0","User 1","User 2","User 3","User 4","User 5","User 6","User 7","User 8","User 9","User 10","User 11","User 12","User 13","User 14","User 15"]}', true); // get array of arrays with `data` key from each data set $users = array_column($a['datasets'], 'data'); // tricky code to sum arrays $sums = array_map('array_sum', array_map(null, ...$users)); // sort array with keeping keys arsort($sums); // we need flip so as `array_replace` will work as expected $keys = array_flip(array_keys($sums)); // "sorting" `data` subarrays foreach ($a['datasets'] as &$item) { $item['data'] = array_replace($keys, $item['data']); } // "sorting" `labels` subarray $a['labels'] = array_replace($keys, $a['labels']); // see the result print_r($a); Fiddle here https://3v4l.org/a7rPL
I see this task as a perfect candidate for array_multisort(). Your synchronously sorted subarrays don't need to retain their initial keys like in u_mulder's output. The first parameter must be the array of columnar sums, then the descending sort flag as the second parameter, then the labels subarray as a reference, then the dynamic number of data subarrays as references to the original array. Code: (Demo) $params = [[], SORT_DESC, &$array['labels']]; foreach ($array['datasets'] as ['data' => &$data]) { foreach ($data as $i => $d) { $params[0][$i] = ($params[0][$i] ?? 0) + $d; } $params[] = &$data; } array_multisort(...$params); var_export($array);
This looks like a typical job for map(reduce).sort: map each element to an object with id, so you can preserve "which user this used to be" information, and total, the result of reducing data. Then sort with a custom sort function (a,b) => a.total - b.total. E.g. function map_total($user, $pos) { return array( "id" => $pos, "total" => array_sum($user.data) ); } function cmp_total($a, $b) { return $a["total"] - $b["total"]; } $mapped = array_map("map_total", $thing.dataset, array_keys($thing.dataset)); $sorted = usort($mapped, "cmp_total");
php merging two arrays into one
I have two arrays that need to be merged together and trying to figure out the correct way of doing it. this is the first array Array ( [IndividualOutmsg] => Array ( [0] => Array ( [user_id] => 3 [number] => 414566765 [msg] => some message ) [1] => Array ( [user_id] => 3 [number] => 410335509 [msg] => any message ) ) ) this is the second array: Array ( [0] => Array ( [0] => OK [1] => 0 [2] => d142b46128b869d0 [3] => 6178977058476937 ) [1] => Array ( [0] => OK [1] => 0 [2] => 60f403f4e243e684 [3] => 6198708709873543 ) ) what i want to get is this: Array ( [IndividualOutmsg] => Array ( [0] => Array ( [user_id] => 3 [number] => 414566765 [msg] => some message [sms_status] => OK [error_code] => 0 [msg_id] => d142b46128b869d0 [msg_id_2] => 6178977058476937 ) [1] => Array ( [user_id] => 3 [number] => 410335509 [msg] => any message [sms_status] => OK [error_code] => 0 [msg_id] => 60f403f4e243e684 [msg_id_2] => 6198708709873543 ) ) )
In that format, you really have to do a lot of the legwork yourself and can't just use array_merge to combine the arrays. It would have to be a more custom job, like so: $count = count($second_array); for($i=0; $i<$count; $i++){ $first_array['IndividualOutmsg'][$i]['sms_status'] = $second_array[0]; $first_array['IndividualOutmsg'][$i]['error_code'] = $second_array[1]; $first_array['IndividualOutmsg'][$i]['msg_id'] = $second_array[2]; $first_array['IndividualOutmsg'][$i]['msg_id2'] = $second_array[3]; } If you were to output the second array with the associative keys set, it would be much easier to combine them using array_merge, provided the keys didn't conflict. $count = count($second_array); for($i=0; $i<$count; $i++){ $first_array['IndividualOutmsg'][$i] = array_merge($first_array['IndividualOutmsg'][$i], $second_array[$i]); }
http://au.php.net/manual/en/function.array-merge.php Array merge might be what you're looking for... Though you'll need to probably write a loop or function that can get to the right place in your multi-dimensional array, perform the merge and also change the relevant keys.