How to get the intersection of an array of multidimensional arrays? - php

I have an array of multidimentional arrays. Each array represents a result set from a search. I am having trying to figure out how to filter this set of data to only include arrays that are present in each array.
Note: The index's shown below each represent multidimentional arrays. Each array has a deeply nested Id key that can be used for comparison.
The Id is located at:
$reference_variable['data']['Id'][0]
For example,
array(
array([0], [19], [21], [148]),
array([2], [21], [32], [44], [432], [549]),
array([13], [21], [148])
)
Should return:
array(
[21]
)
and:
array(
array([0], [12], [15]),
array([2], [21], [32], [44], [432], [549]),
array([13], [21], [148])
)
Should return:
array(
[]
)
What is the best way to handle this? array_intersect does not work well with multidimensional arrays.
I've already tried storing all Ids in an array, and using array_count_values to find duplicate Ids, and then use array_filter to compare if the Id of the current array was equal to any of the duplicate Id's.
But that turned out to be totally wrong since this method would allow:
array(
array([0], [19], [21], [148]),
array([2], [21], [32], [44], [432], [549]),
array([13], [21], [148])
)
To return:
array(
[21, 148]
)
Which is not the intersection of all arrays.

Just store the indexes of the first array in an array. Check for matching indexes on the second array and store those in a second array A2. Check for matches between the second stored array ( A2 ) and the third array. Call it A3 for consistency ( A3 ). This is your answer.
Maybe 10-20 lines of code.

This was the answer in my case:
$params = array_merge($array_of_arrays, array('array_compare'));
$intersection = call_user_func_array('array_uintersect', $params);
function array_compare($a1, $a2)
{
if ($a1 === $a2) {
return 0;
}
if ($a1 > $a2) {
return 1;
}
return -1;
}
Credit: https://stackoverflow.com/a/2020654/1911755

Related

How do I reorganize an array in PHP?

I am trying to figure out how to reorganize an array..
I have a multidimensional array(Ill call that original_array) and I would like to take the first array within original_array and set the values as keys in a new array. I also want to take the values of the second array in original_array and make them keys and then set the values of the third array in original_array as the values for those keys.
Here is an example of original_array:
Array (
[id] => Array (
[0] => 1
[1] => 3
)
[reward] => Array (
[0] => Movie
[1] => Trip
)
[cost] => Array (
[0] => 50
[1] => 200
)
)
Basically what I would like to do is look like this:
Array (
[1] => Array (
[Movie] => 50
)
[3] => Array (
[Trip] => 200
)
)
Is there a simple and elegant way to merge these like this?
I have spent hours trying to figure this out using array_merge, array_merge_recursive.. etc. And have search SO far and wide for a similar questions, but I haven't found anything that does what I am after.
I was able to correctly combine the 2nd and 3rd arrays in original_array with array_combine. But, I am at a loss as how to combine that result with the 1st array's values in original_array.
Thanks in advance to any help!
Well, the dirty way would be just use combine array functions like array_combine with the input:
$new_array = array_combine(
$array['id'], // parent keys
// combine chunked combined sub keys :p
array_chunk(array_combine($array['reward'], $array['cost']), 1, true)
);
There may be some incantation of array_*() merging functions that could produce what you're looking for, but it is far easier to just iterate over the original array's [id] sub-array and use its values to create new sub-array keys in a different output array.
// To hold your output
$output = array();
// Iterate the original array's [id] sub-array
foreach ($original['id'] as $idxkey => $newkey) {
// Add a sub-array using $newkey to the output array
$output[$newkey] = array(
// Using the index (not value), retrieve the corresponding reward
// value to use as the new array key
// and corresponding cost to use as the new subarray value
$original['reward'][$idxkey] => $original['cost'][$idxkey]
);
}
Here is a demonstration: https://3v4l.org/2pac3
This should work for you:
First you can get the keys for the main array into a separate variable with array_shift(), which will just remove the first element from your array, which is the array holding the keys.
Then use array_map() to loop through both of your subArrays and use reward as key with the cost values as value and return it in an array. At the end you just have to array_combine() your keys $keys with the new created array.
Code:
<?php
$keys = array_shift($arr);
$result = array_combine($keys, array_map(function($k, $v){
return [$k => $v];
}, $arr["reward"], $arr["cost"]));
print_r($result);
?>
You might wanna take a look at BaseArrayHelper from Yii 2.0 Framework.
Although this file is part of a framework it has only very few dependencies and you should be able to use just this file or parts of it in your code with small modifications.
An example for your use case can be found in the index() method.

How to compare two arrays and add keys from one array to another

I have two arrays
1st array
first array containts 60 strings like this:
['string1','string2', ... , string60];
2nd array
And I have an associative array like this:
['Key' => value, ..., 'Key' => value]
What I need to do is compare each value from first array(that contains 60 ellements), with each key from the second array, and if second(associative) array doesn't contain key that matches any value from first array - I should add such ellement to the associative array.
For example second array doesn't have key that matches string5 for example, and I'm not talking about value of the key, I'm literally talking about Key itself. So now I need to add string5 as a new key => value ellement to the array, the Key must be the word string5, and the value must be empty.
What is the best way to do it?
Not more complicated than:
$combined = $array2 + array_fill_keys($array1, null);
array_fill_keys creates an array like ['string1' => null, ..], + adds all of these keys which don't already exists in $array2.
$combined = $array2 + array_fill_keys($array1, null);// key value will be maintained
array_values($array2); //index starts from 0
This should work
foreach($array_1 as $val) {
if(!isset($array_2[$val])) {
$array_2[$val] = null;
}
}
pretty sure there are people who know more efficient ways (resource wise) as this might take long when you have huge arrays.
Here is the logical way to do this.
First divide the second array in key and values array. I mean two different array.
So
$keys = array_keys($array2);
$values = array_values($array2);
now you have to take the different from $array1 to $array2 sigular or vice-versa ( Depends on your requirement ) and it will give you the difference of missing keys.
$diff = array_diff($array1,$keys);
Now you will be able to find it easily.
Please refer to array_diff Source: php.net
<?php
$required = array('key1', 'key2', 'key3','key4');
$data = array(
'key1' => 10,
'key2' => 20
);
$arrayDiff = array_diff_key(array_flip($required),$data);
$final = array_merge($data,$arrayDiff);
// Result
// Array
//(
// [key1] => 10
// [key2] => 20
// [key3] => 2
// [key4] => 3
//)
?>
If you want default value to be populated to the new keys added to the array, add below line before merge and use the variable $arrayFill instead of $arrayDiff in the merge statement
$arrayFill = array_fill_keys(array_flip($arrayDiff),0);

Compare 2 arrays on single element in php

I have two arrays that look like this with many more results:
Array
(
[0] => Array
(
[comName] => John
[locID] => L152145
[locName] => Johns House
)
)
What i'd like to do is compare the results but only on the locName element...here is the code i'm working with thus far.
$searchcode = "a url to json results";
$simple = file_get_contents($searchcode);
$arr = json_decode($simple , true);
do this for each json file then
$result = array_intersect($arr, $anotherarr);
Ideally this would return the matching locNames from both arrays
Thanks for the help!
What you are a looking for is function array_uintersect:
$result = array_uintersect($arr, $anotherarr, function($a, $b) { return strcmp($a['locName'], $b['locName']); });
If each locName will appear only once, then I suggest you transform your array in an associative one in the form
Array
(
[Johns House] => Array
(
[comName] => John
[locID] => L152145
[locName] => Johns House
)
)
This way, you'll have access to every location name using array_keys, and will be able to pick the locations that are present in both arrays with a simple array_intersect on both array_keys.
The simplest way to do this is to iterate over the original array filling a new one (not really efficient if you're planning to manage 10000+ elements, but negligible in other case)
$assocA=array();
$assocB=array();
foreach($arr as $element) {
$assocA[$element['locName']]=$element;
}
foreach($anotherarr as $anotherelement) {
$assocB[$anotherelement['locName']]=$anotherelement;
}
$common_locations = array_intersect(array_keys($assocA), array_keys($assocB)); // will return all locnames present in both arrays.

PHP - how to sort multidimensional array by comparing two different sub array values

Im so tired of finding the way to sort this multidimensional array.
I have tried usort() but it doesnt sort the way I want to. Or just maybe I could not figure out the correct logic to use. usort() seems hard to understand for me.
I wanted to sort my data(example below), by finding first which has the higher value (between keys a and b) for each of the sub arrays. And then the sub array which has the highest value either from its keys a or b will be on top.
For example this array:
Array
(
[0] => Array
(
[a]=>5
[b]=>
[c]=>apple
)
[1] => Array
(
[a]=>5
[b]=>7
[c]=>guava
)
[2] => Array
(
[a]=>6
[b]=>
[c]=>banana
)
[3] => Array
(
[a]=>5
[b]=>
[c]=>avocado
)
)
should be sorted like this:
Array
(
[0] => Array
(
[a]=>5
[b]=>7
[c]=>guava
)
[1] => Array
(
[a]=>6
[b]=>
[c]=>banana
)
[2] => Array
(
[a]=>5
[b]=>
[c]=>apple
)
[3] => Array
(
[a]=>5
[b]=>
[c]=>avocado
)
So how exactly I am able to do this? Im so confused how to use usort. What is the best PHP function for sorting this?
The way usort() works is that it requires a way to compare the elements of the array to each other to decide what comes first. You provide it a function, and it calls that function for each element pair in the input array. If the function returns a negative value, it means the first argument is less than the second argument and should come before it in the sorted array. The opposite is true if it returns a positive value.
Let's say you're comparing two sub-arrays s1 and s2. Using the logic you provided, s1 is "less than" s2 -- that is, s1 should come before s2 -- if max(s1.a,s1.b) > max(s2.a,s2.b). Thus, the sort function should return a negative value if this is true. If you subtract s1's max from s2's max, this should yield the proper result.
Try this:
function sort_function(array $arr1, array $arr2) {
$arr1_val = max($arr1['a'],$arr1['b']);
$arr2_val = max($arr2['a'],$arr2['b']);
return $arr2_val - $arr1_val;
}
usort($arr,sort_function);
Assuming $arr is your array.
Your comparison function:
function cmp($a,$b){
// clean up the keys so they don't cause weird cross-type comparisons
(empty($a['a']) ? $a['a'] = 0 : NULL;
(empty($a['b']) ? $a['b'] = 0 : NULL;
(empty($b['a']) ? $b['a'] = 0 : NULL;
(empty($b['b']) ? $b['b'] = 0 : NULL;
/// figure out the pertinent value to compare
$value_from_a_to_compare = max($a['a'],$a['b']);
$value_from_b_to_compare = max($b['a'],$b['b']);
if($value_from_a_to_compare == $value_from_b_to_compare) {
return 0;
}
if($value_from_a_to_compare > $value_from_b_to_compare) {
return 1;
} else {
return -1;
}
}
Call this from usort
usort($your_array,'cmp');
var_dump($your_array);
There are several methods, including writing the function written by dethtron5000 that would enable you to use usort.
I will describe a different suggestion: create a secondary array, in which you put the highest numbers from the first array and then use array_multisort to sort both, using the values from the secondary array.
$helper = array();
foreach ($data as $value)
{
$helper[] = max($value['a'],$value['b']);
}
array_multisort($helper,$data);

How to sort an array based on input array?

I'm having trouble sorting an array according to another array. I've tried usort, uksort and uasort but I'm getting nowhere. Other questions on stackoverflow are not directly applicable here, as my array structure is different. I want to sort this multidimensional array:
$main = Array (
[Technology] => Array ()
[World] => Array ()
[Europe] => Array ()
)
By using this index-array:
$index = Array (
[0] => Europe
[1] => Technology
[2] => World
)
Basically, in this example I would want Europe to come first in the $main array, Technology second and World third, as this is their positioning in the $index array. How do I do that? (Please disregard little syntax errors in the arrays above)
$main_sort = array()
foreach ($index as $key => $value) {
if ($main [$value]) $main_sorted [$value] = $main [$value];
}
Simply loop through the $index array and map those values to a new array using the values from the $main array.
Given $index and $main,
uksort($main, function ($k, $k2) use ($index) {
return array_search($k, $index) - array_search($k2, $index);
});
Array will be sorted according to keys specified in $index. Behavior of not-matched keys is unspecified.
This solution works if you don't have any value in $index which is not a key in $main (as is the case in your example):
$sorted = array_merge(array_flip($index), $main);
If the values of $index are a superset of the keys of $main, a possible solution is:
$sorted = array_intersect_assoc(array_merge(array_flip($index), $main), $main);
Keep in mind that letting PHP functions work on arrays is much faster than doing so "explicitly"

Categories