To compare two arrays while considering duplicate value - php

i have two arrays
$array1 = array(1, 2, 2, 3);
$array2 = array( 1, 2, 3,4);
and when did :
var_dump(array_diff($array1, $array2));
getting :
array(0){}
as output , but i am looking for :
array(1){[2]=>2}
can someone please let me know how to do it
Thanks in Advance

Try this
$array1 = array(1, 2, 2, 3, 4, 5, 5, 7);
$array2 = array(1, 2, 4, 6, 3, 3, 5);
$diff = array_filter($array1,
function ($val) use (&$array2) {
$key = array_search($val, $array2);
if ( $key === false ) return true;
unset($array2[$key]);
return false;
}
);
print_r($diff);
// Array ( [2] => 2 [6] => 5 [7] => 7 )

If you want to count number of duplicate element from same array as well as from multiple arrays, please use below code,
<?php
$array1 = array(1,2,2,3,7);
$array2 = array(1,2,3,4);
$diff_array = array();
$diff_array1 = array_count_values($array1);
$diff_array2 = array_count_values($array2);
$a = array_keys($diff_array1);
$b = array_keys($diff_array2);
for($i=0;$i<count($a);$i++)
{
if($a[$i] == $b[$i])
{
$x = $a[$i];
$y = $b[$i];
$diff_array1[$x] += $diff_array2[$y];
}
}
$diff_array1=array_diff($diff_array1, array('1'));
echo '<pre>';
print_r($diff_array1);
?>

This will get you the desired result:
$array1 = array(1, 2, 2, 3);
$array2 = array( 1, 2, 3,4);
$countArray1 = array_count_values($array1);
$countArray2 = array_count_values($array2);
foreach($countArray1 as $value=>$count) {
if($count > 1) $dupArray[] = $value;
}
foreach($countArray2 as $value=>$count) {
if($count > 1) $dupArray[] = $value;
}
print_r($dupArray);
Result
Array
(
[0] => 2
)
Explanation
Using array_count_values will count all the values of an array, which would look like:
Array
(
[1] => 1
[2] => 2
[3] => 1
)
Array
(
[1] => 1
[2] => 1
[3] => 1
[4] => 1
)
We then iterate through each array_count_values to locate values that occur more than once. This will work when you have more than one set of duplicate values:
$array1 = array(1, 2, 2, 3);
$array2 = array( 1, 2, 3, 4, 3);
Result
Array
(
[0] => 2
[1] => 3
)

While it may be less elegant, the simple way to do this is with a for loop:
$diff_array = array();
for ($i = 0; ($i < count($array1)) and ($i < count($array2)); $i++)
{
if ($array1[$i] !== $array2[$i]) { $diff_array[$i] = $array1[$i]; }
}

Related

Make new array values from element value plus the previous element's value

I have array like this :
$array = array(1, 4, 8, 3, 7);
I want sum the value of array but first, I unshift the array like this :
<?php
$array = array(1, 4, 8, 3, 7);
array_unshift($array, 0);
array_pop($array);
foreach($array as $key => $val) {
echo $val;
}
?>
then I want sum array first (1, 4, 8, 3, 7) with new array (0, 1, 4, 8, 3)
sum like 1 plus 0 and 4 plus 1 and 8 plus 4 etc
And I want the output is : 1, 5, 12, 11, 10
Just use array_map.
array_map allows you to use a custom function on multiple arrays at the same time
$array = array(1, 4, 8, 3, 7);
$others = $array;
array_unshift($others, 0);
array_pop($others);
function sumarray($v1,$v2){
return $v1+$v2;
}
$res = array_map('sumarray', $array,$others);
print_r($res);
result like
Array
(
[0] => 1
[1] => 5
[2] => 12
[3] => 11
[4] => 10
)
You can use for loop instead of foreach.
Example
$array = $array2 = array(1, 4, 8, 3, 7);
array_unshift($array, 0);
array_pop($array);
$array3 = [];
for($i = 0; $i < count($array); $i++) {
$array3[] = $array[$i]+$array2[$i];
}
print_r($array3);
Output
Array
(
[0] => 1
[1] => 5
[2] => 12
[3] => 11
[4] => 10
)
You can store the popped value in a variable (popped) so you can use it later. Then you can use a regular for loop to loop over your array and add the popped value to the array once the loop is complete:
$array = array(1, 4, 8, 3, 7);
array_unshift($array, 0);
$popped = array_pop($array);
$result = [];
for($i = 0; $i < count($array)-1; $i++) {
$val1 = $array[$i];
$val2 = $array[$i + 1];
$result[] = $val1 + $val2;
}
$result[] = end($array) + $popped; // add the last element with the popped value
print_r($result);
Output:
Array ( [0] => 1 [1] => 5 [2] => 12 [3] => 11 [4] => 10 )
There is no need to pop or shift any elements and there is no need to create a copy of the input array.
As you iterate the input array, sum the current value with the previous value. If there is no previous value, use zero. This is exceedingly simple since your input is an indexed array.
Code: (Demo)
$array = [1, 4, 8, 3, 7];
$result = [];
foreach ($array as $index => $value) {
$result[] = $value + ($array[$index - 1] ?? 0);
}
var_export($result);
// [1, 5, 12, 11, 10]

Filter 2d array to keep all rows which contain a specific value

I have a two dimensional haystack array like this:
[
4 => [0, 1, 2, 3, 10],
1 => [0, 1, 2, 3, 10],
2 => [0, 1, 2, 3],
3 => [0, 1, 2, 3]
]
Let's say that I have a search value of $x = 10.
How can I search in above array and get an array index which contains $x.
In my current example, subarrays with key 4 and 1 contain value of $x -- I need those 2 subarrays.
You could loop then use array_search()
$array = array(...); // Your array
$x = 10;
foreach ($array as $key => $value) {
if (array_search($x, $value)) {
echo 'Found on Index ' . $key . '</br>';
}
}
Or if you need the arrays with those index
$array = array(...); // Your array
$x = 10;
$result = array(); // initialize results
foreach ($array as $key => $value) {
if (array_search($x, $value)) {
$result[] = $array[$key]; // push to result if found
}
}
print_r($result);
You can use array_filter() to keep only the array that contains the value you want:
$array = array(
array(0, 1, 2, 3, 10),
array(0, 1, 2, 3, 10),
array(0, 1, 2, 3),
array(0, 1, 2, 3)
);
$x = 10;
$out = array_filter($array, function($arr) use($x) {
return in_array($x, $arr);
});
print_r($out);
Output:
Array
(
[0] => Array
(
[0] => 0
[1] => 1
[2] => 2
[3] => 3
[4] => 10
)
[1] => Array
(
[0] => 0
[1] => 1
[2] => 2
[3] => 3
[4] => 10
)
)
You can use as well in_array
$array = array(); // Your array
$x = 10;
$result = array(); // initialize results
foreach ($array as $key => $value) {
if (in_array($x, $value)) {
$result[] = $array[$key]; //
}
}
print_r($result)
You can use array_search() function to search the value in array..
Link: http://php.net/manual/en/function.array-search.php
For Exp:
$x = 10; // search value
$array = array(...); // Your array
$result = array(); // Result array
foreach ($array as $key => $value)
{
if (array_search($x, $value))
{
$result[] = $array[$key]; // push the matched data into result array..
}
}
print_r($result);
You can use array_search();
doc: http://www.php.net/manual/en/function.array-search.php

Getting specidic values from PHP arrays

Is there a way to get the first value from array, then the first value key + 3 ; then +6 then + 9 ans so on
Take this array for example,
array(1,2,5,14,19,2,11,3,141,199,52,24,16)
i want extract a value every 3 so the result would be
array(1,14,11,199,16)
Can i do that with existing PHP array function?
Use a for loop and increment the counter variable by 3.
for ($i = 0; $i <= count(your array); $i+3) {
echo $myarray[i]
}
The following is function that will handle extracting the values from a given array. You can specify the number of steps between each value and if the results should use the same keys as the original. This should work with regular and associative arrays.
<?php
function extractValues($array, $stepBy, $preserveKeys = false)
{
$results = array();
$index = 0;
foreach ($array as $key => $value) {
if ($index++ % $stepBy === 0) {
$results[$key] = $value;
}
}
return $preserveKeys ? $results : array_values($results);
}
$array = array(1, 2, 5, 14, 19, 2, 11, 3, 141, 199, 52, 24, 16);
$assocArray = array('a' => 1, 'b' => 2, 'c' => 5, 'd' => 14, 'e' => 19, 'f' => 2, 11, 3, 141, 199, 52, 24, 16);
print_r(extractValues($array, 3));
print_r(extractValues($array, 3, true));
print_r(extractValues($assocArray, 5));
print_r(extractValues($assocArray, 5, true));
?>
Output
Array
(
[0] => 1
[1] => 14
[2] => 11
[3] => 199
[4] => 16
)
Array
(
[0] => 1
[3] => 14
[6] => 11
[9] => 199
[12] => 16
)
Array
(
[0] => 1
[1] => 2
[2] => 52
)
Array
(
[a] => 1
[f] => 2
[4] => 52
)
Use a loop and check the key.
$result = array();
foreach($array as $key => $value) {
if ($key % 3 === 0) {
$result[] = $value;
}
}
Try below one:
<?php
$your_array = array (1,2,5,14,19,2,11,3,141,199,52,24,16);
$every_3 = array();
$i = 0;
foreach($your_value as $value) {
$i++;
if($i%3==0){
$every_3[]=$value;
}
}
var_dump($every_3);
?>
Do like this
$arr=array (1,2,5,14,19,2,11,3,141,199,52,24,16);
$narr=array();
for($i=0;$i<count($arr);$i=$i+3){
$narr[]=$arr[$i]
}
print_r($narr);
<?php
$mynums = array(1,2,5,14,19,2,11,3,141,199,52,24,16);
foreach ($mynums as $key => $value) {
if ( $key % 3 === 0)
{
$newnum[] = $value;
}
}
var_dump($newnum);
?>
$data = array(1,2,5,14,19,2,11,3,141,199,52,24,16);
$matches = array();
foreach($data as $key => $value)
{
if($key%3 === 0)
{
$matches[] = $value;
}
}
var_dump($matches);
The only way you could do it would be to use a loop, count the length of an array, and loop through using a % mathmatical operator.
It gives you a remainder of a division: http://au2.php.net/operators.arithmetic

PHP Search array recursively and return count of index?

Is there a PHP function that lets you search an array recursively and return the number of instances a certain key 'x' occurs (regardless of how deep)?
I would use array_walk_recursive(). Example:
$a = array(1,2,3,'x',array(4,5,'x',array(6,7,8,'x')));
$v = "x";
$i = 0;
array_walk_recursive($a, function($val, $key) use (&$i, $v) {
if ($val == $v) {
$i++;
}
});
echo $i;
Output:
3
You can traverse the array recursively (that is regardless of the depth) and then count the values:
$array = array(1, 2, 3, 'x', array(4, 5, 'x', array(6, 7, 8, 'x')));
$rit = new RecursiveIteratorIterator(new RecursiveArrayIterator($array));
$xCount = 0;
foreach ($rit as $value) {
if ($value === 'x') {
$xCount++;
}
}
var_dump($xCount); # int(3)
A variation of this is to convert this iteration into an array again and count values:
$array = array(1, 2, 3, 'x', array(4, 5, 'x', array(6, 7, 8, 'x')));
$rit = new RecursiveIteratorIterator(new RecursiveArrayIterator($array));
$allCount = array_count_values(iterator_to_array($rit, FALSE));
print_r($allCount);
Output/Result:
Array
(
[1] => 1
[2] => 1
[3] => 1
[x] => 3
[4] => 1
[5] => 1
[6] => 1
[7] => 1
[8] => 1
)
See as well:
How do I use a recursive array iterator to process a multidimensional array?
You could write a simple recursive function that does what you want. I didn't test this, but the idea would be something like:
$count = 0;
function findKey($array,&$count){
if(!empty($array)){
foreach($array as $key => $childArray){
if($key == 'keyImLookingFor'){
$count++;
}
findKey($childArray,$count);
}
}
}
$count should then contain your number of key occurrences. Again, this might need some cleanup.
$array = array(
'key1' => 'val1',
'key2' => 'val2',
'key3' => array('key1' => 'val3'));
$count = 0;
function key_count($val, $key){
global $count;
if($key == "key1"){
$count++;
}
}
array_walk_recursive($array, 'key_count');
echo $count;

Reference detection in array from another function

So I'm using the pin method, but the reference is detected one level too late:
$pin = time();
function wrap($arr){
test($arr);
}
function test(&$arr){
global $pin;
if(in_array($pin, $arr))
return print "ref";
$arr[] = $pin;
foreach($arr as &$v){
if($v != $pin){
if(is_array($v))
return test($v);
print $v . " ";
}
}
}
$array = array(1, 2, 3);
$array[4] = &$array;
wrap($array);
I get 1 2 3 1 2 3 rec
But I expect 1 2 3 rec
If I just do test($arr) then it works, but the problem is that I need to wrap the test function inside another one that accepts values not references :(
Is there any way I can detect the reference at the right moment with my wrapper function too?
Introduction
I think a better approach would be to create a copy of the array and compare modification rather than use global pin and it can still be a 100% Recursive
Example 1
This is from your example above :
$array = array(1,2,3);
$array[4] = &$array;
wrap($array);
Output
Array
(
[0] => 1
[1] => 2
[2] => 3
[4] => ref
)
Example 2
Are we really sure its detecting reference or just a copy of the array
//Case 1 : Expect no modification
$array = array(1, 2, 3, array(1, 2, 3));
wrap( $array);
//Case 2 : Expect Modification in Key 2
$array = array(1, 2, 3, array(1, 2, 3));
$array[2] = &$array;
wrap( $array);
Output
Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => Array
(
[0] => 1
[1] => 2
[2] => 3
)
)
Array
(
[0] => 1
[1] => 2
[2] => ref
[3] => Array
(
[0] => 1
[1] => 2
[2] => 3
)
)
Example 3
Is this really recursive ?
$array = array(1, 2, 3, array(1, 2, 3));
$array[4][4][2][6][1] = array(1,2,3=>&$array);
wrap( $array);
Output
Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => Array
(
[0] => 1
[1] => 2
[2] => 3
)
[4] => Array
(
[4] => Array
(
[2] => Array
(
[6] => Array
(
[1] => Array
(
[0] => 1
[1] => 2
[3] => ref <-- GOT YOU
)
)
)
)
)
)
Your Modified Function
/**
* Added printf since test now returns array
* #param array $arr
*/
function wrap(array $arr) {
printf("<pre>%s<pre>", print_r(test($arr), true));
}
/**
* - Removed Top Refrence
* - Removed Global
* - Add Recursion
* - Returns array
* #param array $arr
* #return array
*/
function test(array $arr) {
$temp = $arr;
foreach ( $arr as $key => &$v ) {
if (is_array($v)) {
$temp[$key]['_PIN_'] = true;
$v = isset($arr[$key]['_PIN_']) ? "ref" : test($v);
}
}
unset($temp); // cleanup
return $arr;
}
I think you are over-complicating things. I solved this by looping over the array and checking if the current value in the array is equivalent (===) with the array.
function wrap( $arr){
test($arr);
}
function test( $arr){
foreach( $arr as $v) {
if( $v === $arr) {
print 'ref, ';
} else {
if( is_array( $v)) {
test( $v);
} else {
print $v . ', ';
}
}
}
}
I used the following test cases:
echo "Array 1:\n";
$array1 = array(1, 2, 3);
$array1[4] = &$array1;
wrap( $array1);
echo "\nArray 2:\n";
$array2 = array(1, 2, 3, array(1, 2, 3));
$array2[2] = &$array2;
wrap( $array2);
Which produced this output:
Array 1:
1, 2, 3, ref
Array 2:
1, 2, ref, 1, 2, 3,
However, the above method will fail for nested references. If nested references are possible, as in the following test case:
echo "\nArray 3:\n";
$array3 = array(1, 2, 3, array(1, 2, 3));
$array3[3][2] = &$array3;
wrap( $array3);
Then we need to keep track of all the array references we've seen, like this:
function wrap( $arr){
test( $arr);
}
function test( $arr){
$refs = array(); // Array of references that we've seen
$f = function( $arr) use( &$refs, &$f) {
$refs[] = $arr;
foreach( $arr as $v) {
if( in_array( $v, $refs)) {
print 'ref, ';
} else {
if( is_array( $v)) {
$f( $v);
} else {
print $v . ', ';
}
}
}
};
$f( $arr);
}
Using the above test case, this outputs:
Array 3:
1, 2, 3, 1, ref, 3,
Edit: I've updated the final function that keeps track of all references to eliminate the global dependencies.
function wrap($arr){ test($arr); }
/// ...
wrap($array);
Your wrap() function allocates new memory block for $arr. When you calling test() function within wrap()s body, it takes reference of $arr memory block, but not an $arrays memory block, because $arr is a copy of $array and PHP memory management system stores them separately.
There is a universal reference spotting function:
function is_equal_refs(&$a, &$b){
$buffer = $a; // saving current value in temporary variable
$a = md5(time()); // assigning new value to memory block, pointed by reference
$result = ($a === $b); // if they're still equal, then they're point to the same place.
$a = $buffer; // restoring value
return $result; // returning result
}
So, lets do some testing:
<?php
header('Content-Type: text/plain');
function is_equal_refs(&$a, &$b){
$buffer = $a;
$a = md5(time());
$result = ($a === $b);
$a = $buffer;
return $result;
}
function wrap($arr){ test($arr); }
function test(&$arr){
foreach($arr as &$v){
if(is_equal_refs($arr, $v)){
print_r('ref');
echo PHP_EOL;
break;
}
if(is_array($v))return test($v);
print_r($v);
echo PHP_EOL;
}
}
$array = array(1, 2, 3);
$array[] = &$array;
wrap($array);
?>
Shows:
1 // < $arr
2
3
1 // < $array
2
3
ref // < $array doubled -> reference found
The reason of such behavior is $arr[3] contains reference for $arrays memory block, but not reference of itself's memory block.
Lets remove a $array[] = &$array; row, and modify wrap() function to check:
function wrap($arr){
$arr[] = &$arr;
test($arr);
}
And result would be:
1 // < $arr
2
3
ref // < $arr doubled -> reference found
Because $arr not points to $array, but to itself in $arr[3]. So, in your code there are different references you want to spot.
CONCLUSION: What you want to achieve is breaking out PHP memory management rules.
UPDv1:
Need to seek a workaround, to restore $array reference in a wrap() function scope.
1) A "bad" / "globals" practice:
<?php
header('Content-Type: text/plain');
function is_equal_refs(&$a, &$b){
$buffer = $a;
$a = md5(time());
$result = ($a === $b);
$a = $buffer;
return $result;
}
function wrap($array){
global $check; // <- THIS
test(empty($check) ? $array : $check); // <- THIS
}
function test(&$arr){
foreach($arr as &$v){
if(is_equal_refs($v, $arr)){
print_r('ref');
echo PHP_EOL;
break;
}
if(is_array($v)){
test($v);
} else {
print $v . ' ';
echo PHP_EOL;
}
}
}
$array = array(1, 2, 3);
$array[] = &$array;
$check = &$array; // <- and THIS
wrap($array);
?>
Which shows:
1
2
3
ref
2) A "wrap everything in array or object" practice: (prefered and reliable)
<?php
header('Content-Type: text/plain');
define('REF_MARKER', 'x-my-tr!cky-ref'); // trick key definition
function is_equal_refs(&$a, &$b){
$buffer = $a;
$a = md5(time());
$result = ($a === $b);
$a = $buffer;
return $result;
}
function wrap(array $arr){
// restore reference, if trick.
// it might be moved to the top part of test() function (might affect performance).
if(isset($arr[REF_MARKER]))$arr = &$arr[REF_MARKER];
test($arr);
}
// $array - subject to test;
// $refs - internal ref list of all `subjects`;
function test(&$array, $refs = array()){
$refs[] = &$array;
foreach($array as &$value){
foreach($refs as &$ref){
if(is_equal_refs($ref, $value))return print 'ref ';
}
if(is_array($value)){
$refs[] = &$value;
test($value, $refs);
} else {
print $value . ' ';
}
}
}
$array = array(1, 2, 3);
$array[] = &$array;
wrap(array(REF_MARKER => &$array)); // trick
print PHP_EOL;
$ring = array(1, 2, 3, array(4, 5, 6));
$ring[3][] = &$ring;
wrap(array(REF_MARKER => &$ring)); // trick
print PHP_EOL;
$test = array('a', 'b', 'c');
$ring = array(1, 2, 3);
$ring[] = &$test;
$test[] = &$ring;
wrap(array(REF_MARKER => &$ring)); // trick
print PHP_EOL;
wrap(range(1, 5)); // normal
print PHP_EOL;
$test = array(1, 2, 3, array(1, 2, 3), 4, array(5, 2, 3), array(6, array(1, 2, 3), 7), array(1, 2, 3));
wrap($test); // normal
print PHP_EOL;
$test[] = &$test;
$test[3][] = &$test;
$test[5][] = &$test[3];
wrap(array(REF_MARKER => &$test)); // trick
?>
Shows:
1 2 3 ref
1 2 3 4 5 6 ref
1 2 3 a b c ref
1 2 3 4 5
1 2 3 1 2 3 4 5 2 3 6 1 2 3 7 1 2 3
1 2 3 1 2 3 ref 4 5 2 3 ref 6 1 2 3 7 1 2 3 ref

Categories