Create a 'results' array based on comparison of two two-dimensional arrays? - php

I have two two-dimensional arrays I'd liked to compare to one another:
$array1
Array
(
[0] => Array
(
[A] => GB
[B] => Harry
[C] => British Army
[D] => Eton College
[E] => Cressida Bonas
)
[1] => Array
(
[A] => GB
[B] => William
[C] => Royal Air Force
[D] => Eton College
[E] => Catherine Middleton
)
)
$array2
Array
(
[0] => Array
(
[A] => GB
[B] => Harry
[C] => British Army
[D] => Eton College
[E] => Cressida Bonas
)
[1] => Array
(
[A] => GB
[B] => James
[C] => British Army
[D] => Millfield
[E] => Unknown
)
)
And produce a boolean true/false results array as follows if any of the child array values differ:
$results_array
Array
(
[0] => Array
(
[0] => true
)
[1] => Array
(
[0] => false
)
)
UPDATE:
Both arrays will always have the same length parent arrays (but the child arrays values may vary in length).
I can't wrap my head around how to use foreach in a recursive manner to get the results array.
Any general ideas or advice?

You could do using == operator. Passing the first array as key-array ($k=>$arr) [since the value is another array]. Now compare the two arrays using the simple == comparison operator. You can even perform strict matching using the === operator.
<?php
$arr1=array(0=>array('A'=>'GB','B'=>'Harry','C'=>'British Army'),1=>array('A'=>'GB','B'=>'William','C'=>'Royal Air Force'));
$arr2=array(0=>array('A'=>'GB','B'=>'Harry','C'=>'British Army'),1=>array('A'=>'GB','B'=>'James','C'=>'British Army'));
foreach($arr1 as $k=>$arr)
{
$resarr[][$k]=($arr==$arr2[$k])? "true" : "false";
}
print_r($resarr);
Demo
OUTPUT :
Array
(
[0] => Array
(
[0] => true
)
[1] => Array
(
[1] => false
)
)

I don't know what you are trying to do with a foreach loop. Are you saying every array will have 2 child arrays or every child array will have 5 values? Regardless, I hope this helps you!
I would use some of these:
array_intersect
array_intersect_assoc
array_diff
array_diff_assoc
Code:
<?php
$array1 = [
[
'A' => 'GB',
'B' => 'Harry',
'C' => 'British Army',
'D' => 'Eton College',
'E' => 'Cressida Bonas',
],
[
'A' => 'GB',
'B' => 'William',
'C' => 'Royal Air Force',
'D' => 'Eton College',
'E' => 'Catherine Middleton',
]
];
// What Values are in common
$result1 = array_intersect_assoc($array1[0], $array1[1]);
print_r($result1);
$array2 = [
[
'A' => 'GB',
'B' => 'Harry',
'C' => 'British Army',
'D' => 'Eton College',
'E' => 'Cressida Bonas',
],
[
'A' => 'GB',
'B' => 'James',
'C' => 'British Army',
'D' => 'Millfield',
'E' => 'Unknown',
]
];
// What values are different
$result2 = array_diff_assoc($array2[0], $array2[1]);
print_r($result2);
// A Way to check numerically
$perfectMatch = 5;
$intersect = array_intersect_assoc($array1[0], $array1[1]);
$intersectCount = count($intersect);
if ($intersectCount != $perfectMatch) {
echo "<br> Not Every value matches.";
} else {
echo "<br> Perfect Match!";
}
To compare the full arrays $array1 and $array2 you can do:
<?php
// (With array code above)
$c1 = count($array1);
$c2 = count($array2);
if ($c1 != $c2) {
echo "<br>Array Children must be the same";
}
$result = [];
for ($i = 0; $i < $c1; $i++) {
$in_common = array_intersect($array1[$i], $array2[$i]);
$result[] = count($intersect);
}
print_r($result);

You can just use array_map(), assuming both arrays are of the same length:
$result = array_map(function($a, $b) {
return [$a == $b]; // create single element boolean array
}, $array1, $array2);
You can use either == or ===; the former (==) will yield true if both arrays have the same key and value pairs, whereas the latter (===) will only yield true if the keys of both arrays are also in the same order.

Some answers use the == operator; however that will not work if the arrays do not have the same key=>value matchings; Try this:
$results = array();
foreach ($array1 as $i => $subarray)
{
/* No need to proceed if subarray[i] does not exist in the second array */
if(!is_array($array2[$i]))
{
$results[$i] = false;
continue;
}
$results[$i] = (count(array_diff($array1[$i], $array2[$i])) == 0) ? true : false;
}
This solution is a bit slower than using the == comparison operator. However using the == will not work for a case like:
$array1 => array(1 => "John", 2 => "James");
$array2 => array(1 => "James", 2 => "John");
Here, the keys are not the same, but the values are duplicated. Solutions using == will return false when comparing these arrays.
$array1 == $array2 // False

Related

Removing duplicates from array + json, problem with array_unique

I have array something like:
Array (
[0]=>{"a":"b", "c":"d", "h":"e"}
[1]=>{"a":"b", "f":"g"}
)
How i can removing duplicates here? I'm trying array_unique, but it's not working.
Expected result:
Array (
[0]=>{"a":"b", "c":"d", "h":"e"}
[1]=>{"f":"g"}
)
In this scenario, you need to be careful with duplicate keys yet different values. So match to remove duplicates has to be on combination of both key and value.
To do this, we can collect all keys in an array say $map and have all values visited for this keys inside that key array.
Now, we can just do an in_array check to get hold of whether we got some key-value pair like this before or not.
Snippet:
$arr = [
[
'a' => 'b',
'c' => 'd',
'h' => 'e'
],
[
'a' => 'b',
'f' => 'g',
'c' => 'f'
],
[
'a' => 'd',
'c' => 'd'
]
];
$map = [];
foreach($arr as $index => $data){
foreach($data as $key => $value){
if(!isset($map[$key])) $map[$key] = [];
if(in_array($value,$map[$key])) unset($arr[$index][$key]);
else $map[$key][] = $value;
}
}
print_r($arr);
Demo: https://3v4l.org/RWcMu
You can do it with array_diff() and unset() functions. But, you need to decode this JSON values firstly:
foreach($ar as $in => &$js){
$ar[$in] = json_decode($js,true);
}
After this $ar has a view like:
Array
(
[0] => Array
(
[a] => b
[c] => d
[h] => e
)
[1] => Array
(
[a] => b
[f] => g
)
)
Here you can apply array_diff() function:
$diff = array_diff($ar[1],array_diff($ar[1],$ar[0]));
It will collect duplicates from [1] index in [0]:
Array
(
[a] => b
)
Now you can unset these values from [1] index:
foreach($diff as $ind=>$uns){
unset($ar[1][$ind]);
}
And finally you can change JSON view back:
foreach($ar as $in=>&$js){
$ar[$in] = json_encode($js);
}
Result would be:
Array
(
[0] => {"a":"b","c":"d","h":"e"}
[1] => {"f":"g"}
)
Demo
If input elements are objects, then use this loop at the first step:
foreach($ar as $in=>&$obj){
$ar[$in] = (array)$obj;
}
Demo

PHP - How do I partially compare elements in 2 arrays

I have 2 arrays:
$arr1 = array('Test', 'Hello', 'World', 'Foo', 'Bar1', 'Bar'); and
$arr2 = array('hello', 'Else', 'World', 'Tes', 'foo', 'BaR1', 'Bar');
I need to compare the 2 arrays and save the position of the matching elements to a 3rd array $arr3 = (3, 0, 2, 4, 5, 6); //expected result, displaying position of matching element of $arr1 in $arr2.
By 'matching' I mean all elements that are identical (ex. World), or partially the same (ex. Test & Tes) and also those elements that are alike but are in different case (ex. Foo & foo, Bar & bar).
I've tried a series of combinations and of various functions without success, using functions like array_intersect(), substr_compare(), array_filter() and more. I'm not asking for the exact solution, just something to get me on the right track because i'm going around in circles all afternoon.
This seemed to work for me, but I'm sure there are some edge cases I'm missing that you'd need to test for:
foreach( $arr1 as $i => $val1) {
$result = null;
// Search the second array for an exact match, if found
if( ($found = array_search( $val1, $arr2, true)) !== false) {
$result = $found;
} else {
// Otherwise, see if we can find a case-insensitive matching string where the element from $arr2 is at the 0th location in the one from $arr1
foreach( $arr2 as $j => $val2) {
if( stripos( $val1, $val2) === 0) {
$result = $j;
break;
}
}
}
$arr3[$i] = $result;
}
It produces your desired output array:
Array ( [0] => 3 [1] => 0 [2] => 2 [3] => 4 [4] => 5 [5] => 6 )
Try array_uintersect() with a callback function that implements your "matching" algorithm.
Looks like you need 2 foreach loops, and stripos (or mb_stripos for Unicode) for comparing.
I came up with this to account for duplicates. It returns both keys and both values so you can compare to see if it's working properly. To refine it, you can just comment out the lines setting the values you don't need. It matches all cases.
<?php
$arr1 = array('Test', 'Hello', 'World', 'Foo', 'Bar1', 'Bar');
$arr2 = array('hello', 'Else', 'World', 'Tes', 'foo', 'BaR1', 'Bar');
$matches = array();
//setup the var for the initial match
$x=0;
foreach($arr1 as $key=>$value){
$searchPhrase = '!'.$value.'!i';
//Setup the var for submatching (in case there is more than one)
$y=0;
foreach($arr2 as $key2=>$value2){
if(preg_match($searchPhrase,$value2)){
$matches[$x][$y]['key1']=$key;
$matches[$x][$y]['key2']=$key2;
$matches[$x][$y]['arr1']=$value;
$matches[$x][$y]['arr2']=$value2;
}
$y++;
}
unset($y);
$x++;
}
print_r($matches);
?>
Output looks like this:
Array
(
[1] => Array
(
[0] => Array
(
[key1] => 1
[key2] => 0
[arr1] => Hello
[arr2] => hello
)
)
[2] => Array
(
[2] => Array
(
[key1] => 2
[key2] => 2
[arr1] => World
[arr2] => World
)
)
[3] => Array
(
[4] => Array
(
[key1] => 3
[key2] => 4
[arr1] => Foo
[arr2] => foo
)
)
[4] => Array
(
[5] => Array
(
[key1] => 4
[key2] => 5
[arr1] => Bar1
[arr2] => BaR1
)
)
[5] => Array
(
[5] => Array
(
[key1] => 5
[key2] => 5
[arr1] => Bar
[arr2] => BaR1
)
[6] => Array
(
[key1] => 5
[key2] => 6
[arr1] => Bar
[arr2] => Bar
)
)
)

Count number of different strings?

I have an array that looks like
Array
(
[1] => Array
(
[0] => Date
[1] => Action
)
[2] => Array
(
[0] => 2011-01-22 11:23:19
[1] => SHARE_TWEET
)
[3] => Array
(
[0] => 2011-01-22 11:23:19
[1] => SHARE_FACEBOOK
)
and many other different values (about 10), what I want to do is I want to count the number of times a string is in the array. I was going to use array_count_values but it doesn't count multidimensional arrays.
Any other options?
This could be done by first flattening the array, and then using array_count_values() on it:
For flattening, here is the trick:
$array = call_user_func_array('array_merge', $arrays);
And then:
$counts = array_count_values($array);
Output:
array (
'Date' => 1,
'Action' => 1,
'2011-01-22 11:23:19' => 2,
'SHARE_TWEET' => 1,
'SHARE_FACEBOOK' => 1,
)
Full code:
$array = call_user_func_array('array_merge', $arrays);
var_export(array_count_values($array));
Any time you're dealing with arrays, especially with loops in PHP I can't string enough suggest you look at the array documentation, You'd be suprised how quickly you realise most of the loops in your code is unnecessary. PHP has a built in function to achieve what you're after called array_walk_recursive. And since you're using PHP5 you can use closures rather that create_function (which can be very troublesome, especially to debug, and can't be optimised by the PHP interpreter afik)
$strings = array();
array_walk_recursive($arr, function($value, $key) use (&$strings) {
$strings[$value] = isset($strings[$value]) ? $strings[$value]+1 : 1;
});
I know, unary statements aren't always clear, but this one is simple enough, but feel free to expand out the if statement.
The result of the above is:
print_r($strings);
Array
(
[Date] => 1,
[Action] => 1,
[2011-01-22 11:23:19] => 2,
[SHARE_TWEET] => 1,
[SHARE_FACEBOOK] => 1,
)
Pseudo Code
$inputArray = // your array as in the example above
foreach ($inputArray as $key => $value) {
$result[$value[1]] = $result[$value[1]] + 1;
}
var_dump($result);
Here is a way to do the job:
$arr = Array (
1 => Array (
0 => 'Date',
1 => 'Action'
),
2 => Array (
0 => '2011-01-22 11:23:19',
1 => 'SHARE_TWEET'
),
3 => Array (
0 => '2011-01-22 11:23:19',
1 => 'SHARE_FACEBOOK'
)
);
$result = array();
function count_array($arr) {
global $result;
foreach($arr as $k => $v) {
if (is_array($v)) {
count_array($v);
} else {
if (isset($result[$v])) {
$result[$v]++;
} else {
$result[$v] = 1;
}
}
}
}
count_array($arr);
print_r($result);
output:
Array
(
[Date] => 1
[Action] => 1
[2011-01-22 11:23:19] => 2
[SHARE_TWEET] => 1
[SHARE_FACEBOOK] => 1
)

Intersecting multidimensional array of varying size

I have a multidimensional array that looks like this:
Array
(
[0] => Array
(
[0] => Array
(
[id] => 3
)
[1] => Array
(
[id] => 1
)
[2] => Array
(
[id] => 2
)
[3] => Array
(
[id] => 5
)
[4] => Array
(
[id] => 4
)
)
[1] => Array
(
[0] => Array
(
[id] => 1
)
[1] => Array
(
[id] => 3
)
[2] => Array
(
[id] => 4
)
[3] => Array
(
[id] => 5
)
)
[2] => Array
(
[0] => Array
(
[id] => 3
)
)
)
I need to find a way to return the intersecting value(s). In this case that would be
[id] => 3
The length of the array could be different, so I can't just use array_intersect().
This would be simple if your arrays contained only integers, but as they contain an another array, it gets a bit more complicated. But this should do it:
function custom_intersect($arrays) {
$comp = array_shift($arrays);
$values = array();
// The other arrays are compared to the first array:
// Get all the values from the first array for comparison
foreach($comp as $k => $v) {
// Set amount of matches for value to 1.
$values[$v['id']] = 1;
}
// Loop through the other arrays
foreach($arrays as $array) {
// Loop through every value in array
foreach($array as $k => $v) {
// If the current ID exists in the compare array
if(isset($values[$v['id']])) {
// Increase the amount of matches
$values[$v['id']]++;
}
}
}
$result = array();
// The amount of matches for certain value must be
// equal to the number of arrays passed, that's how
// we know the value is present in all arrays.
$n = count($arrays) + 1;
foreach($values as $k => $v) {
if($v == $n) {
// The value was found in all arrays,
// thus it's in the intersection
$result[] = $v;
}
}
return $result;
}
Usage:
$arrays = array(
array(array('id' => 3), array('id' => 1), array('id' => 2), array('id' => 5), array('id' => 4)),
array(array('id' => 1), array('id' => 3), array('id' => 4), array('id' => 5)),
array(array('id' => 3))
);
print_r(custom_intersect($arrays));
Result:
Array
(
[0] => 3
)
This function isn't perfect: if you have duplicate ID's in one array, it will not work. That would require a bit more code to first make the array values unique, but this will probably work in your case.
You can use array_uintersect() to get the intersection of arrays using a custom comparison function. You have to call it with call_user_func_array() though, as it expects each array as a separate argument:
//build list of parameters for array_uintersect()
$params = array_merge($input, array('compare_func'));
$result = call_user_func_array('array_uintersect', $params);
function compare_func($a, $b) {
return $a['id'] - $b['id'];
}
You can't simply call array_intersect() with call_user_func_array(), because it seems to compare arrays by comparing their string representation (which will always be 'Array').
$a = array(4,3);
$b = array(4,3,2,1);
$c = array(1,2,3,4,5);
$d = array(5,4,3);
$array = array($a,$b,$c,$d);
for ($i=0; $i<count($array); $i++){
if ($i==0){
$array2 = $array[$i];
} else {
$array2 = array_intersect($array2, $array[$i]);
}
}
print_r($array2);`
Result:
3,4
As mentioned in one of the comments of the php.net website (array_intersect function).
$a = array(1,2,3,4,5,2,6,1); /* repeated elements --> $a is not a set */
$b = array(0,2,4,6,8,5,7,9,2,1); /* repeated elements --> $b is not a set */
$ua = array_merge(array_unique($a)); /* now, $a is a set */
$ub = array_merge(array_unique($b)); /* now, $b is a set */
$intersect = array_merge(array_intersect($ua,$ub));
This will return this array:
Array
(
[0] => 1
[1] => 2
[2] => 4
[3] => 5
[4] => 6
)

How can I merge PHP arrays?

I have two arrays of animals (for example).
$array = array(
array(
'id' => 1,
'name' => 'Cat',
),
array(
'id' => 2,
'name' => 'Mouse',
)
);
$array2 = array(
array(
'id' => 2,
'age' => 321,
),
array(
'id' => 1,
'age' => 123,
)
);
How can I merge the two arrays into one by the ID?
#Andy
http://se.php.net/array_merge
That was my first thought but it doesn't quite work - however array_merge_recursive might work - too lazy to check right now.
This does what Erik suggested (id no. as array key) and merges vlaues in $array2 to $results.
$results = array();
foreach($array as $subarray)
{
$results[$subarray['id']] = array('name' => $subarray['name']);
}
foreach($array2 as $subarray)
{
if(array_key_exists($subarray['id'], $results))
{
// Loop through $subarray would go here if you have extra
$results[$subarray['id']]['age'] = $subarray['age'];
}
}
First off, why don't you use the ID as the index (or key, in the mapping-style array that php arrays are imo)?
$array = array(
1 => array(
'name' => 'Cat',
),
2 => array(
'name' => 'Mouse',
)
);
after that you'll have to foreach through one array, performing array_merge on the items of the other:
foreach($array2 as $key=>$value) {
if(!is_array($array[$key])) $array[$key] = $value;
else $array[$key] = array_merge($array[key], $value);
}
Something like that at least. Perhaps there's a better solution?
<?php
$a = array('a' => '1', 'b' => array('t' => '4', 'g' => array('e' => '8')));
$b = array('c' => '3', 'b' => array('0' => '4', 'g' => array('h' => '5', 'v' => '9')));
$c = array_merge_recursive($a, $b);
print_r($c);
?>
array_merge_recursive — Merge two or more arrays recursively
outputs:
Array
(
[a] => 1
[b] => Array
(
[t] => 4
[g] => Array
(
[e] => 8
[h] => 5
[v] => 9
)
[0] => 4
)
[c] => 3
)
#Andy
I've already looked at that and didn't see how it can help merge multidimensional arrays. Maybe you could give an example.
#kevin
That is probably what I will need to do as I think the code below will be very slow.
The actual code is a bit different because I'm using ADOdb (and ODBC for the other query) but I'll make it work and post my own answer.
This works, however I think it will be very slow as it goes through the second loop every time:
foreach($array as &$animal)
{
foreach($array2 as $animal2)
{
if($animal['id'] === $animal2['id'])
{
$animal = array_merge($animal, $animal2);
break;
}
}
}
foreach ($array as $a)
$new_array[$a['id']]['name'] = $a['name'];
foreach ($array2 as $a)
$new_array[$a['id']]['age'] = $a['age'];
and this is result:
[1] => Array
(
[name] => Cat
[age] => 123
)
[2] => Array
(
[name] => Mouse
[age] => 321
)
<?php
$array1 = array("color" => "red", 2, 4);
$array2 = array("a", "b", "color" => "green", "shape" => "trapezoid", 4);
$result = array_merge($array1, $array2);
print_r($result);
?>
With PHP 5.3 you can do this sort of merge with array_replace_recursive()
http://www.php.net/manual/en/function.array-replace-recursive.php
You're resultant array should look like:
Array (
[0] => Array
(
[id] => 2
[name] => Cat
[age] => 321
)
[1] => Array
(
[id] => 1
[name] => Mouse
[age] => 123
)
)
Which is what I think you wanted as a result.
I would rather prefer array_splice over array_merge because of its performance issues, my solution would be:
<?php
array_splice($array1,count($array1),0,$array2);
?>
$new = array();
foreach ($array as $arr) {
$match = false;
foreach ($array2 as $arr2) {
if ($arr['id'] == $arr2['id']) {
$match = true;
$new[] = array_merge($arr, $arr2);
break;
}
}
if ( !$match ) $new[] = $arr;
}

Categories