1

dear users of StackOverflow. There is some problem.

Array 1:
array: 3 [▼
   0 => "8"
   1 => "13"
   2 => "15"
]

Array 2:
array: 16 [▼
   0 => 7
   1 => 8
   2 => 9
]

array_diff does not work, because in the first number, in the second string.

Please suggest any ideas for solving the issue. I will be happy with any comment. Many thanks.

1
  • What do you want in the result? The ones which don't match or the ones which do? Commented Sep 2, 2018 at 0:25

3 Answers 3

8

You can use array_udiff to compare the arrays using a user-defined callback which converts the values to ints before comparing:

$array1 = array('8', '13', '15');
$array2 = array(7, 8, 9);
$diffs = array_udiff($array1, $array2, function ($a, $b) { return (int)$a - (int)$b; });
print_r($diffs);

Output:

Array
(
    [1] => 13
    [2] => 15
)

Update

It has been pointed out that the desired output hasn't been specified, so here is how to get all unique values:

$diffs1 = array_udiff($array1, $array2, function ($a, $b) { return (int)$a - (int)$b; });
$diffs2 = array_udiff($array2, $array1, function ($a, $b) { return (int)$a - (int)$b; });
$diffs = array_merge($diffs1, $diffs2);
print_r($diffs);

Output:

Array
(
    [0] => 13
    [1] => 15
    [2] => 7
    [3] => 9
)

and all matching values using array_uintersect:

$same = array_uintersect($array1, $array2, function ($a, $b) { return (int)$a - (int)$b; });
print_r($same);

Output:

Array
(
    [0] => 8
)

Note

In PHP7 there is now the spaceship operator (<=>) which can also be used in the comparison function e.g.

$diffs = array_udiff($array1, $array2, function ($a, $b) { return (int)$a <=> (int)$b; });
Sign up to request clarification or add additional context in comments.

8 Comments

What about "7" and "9"?
@James OP wanted to use array_diff, which only returns values in the first array that are not in the second array.
How did I not know about array_udiff ... lol ... guess I never needed it. Subtraction is also an interesting way to do it, if it returns 0 (such as 1-1=0) it's false, pretty nifty Nick +1
@James I think I've covered all bases now :-)
@ArtisticPhoenix thanks - I guess you always did something crazy like having consistent data types?
|
2

You could convert the arrays using array map like this

$a1 = array_map('intval', $a1);
$a2 = array_map('intval', $a2);

Then do your array diff and what not.

@Nick's solution is a bit more elegant.

Because, it's not walking the arrays 2x more then you really need to. Of course if you know which is string then you could just convert that one, but I thought I would post another way to do it...

For testing you can simply do this

$a = [
    "1",
    "2" ,
    "3"
];

var_dump($a);

var_dump(array_map('intval', $a));

Output

array(3) {
  [0]=> string(1) "1"
  [1]=> string(1) "2"
  [2]=> string(1) "3"
}

array(3) {
  [0]=> int(1)
  [1]=> int(2)
  [2]=> int(3)
}

Sandbox

And this shows that it does convert the values to string, which was pretty obvious, but I like examples. So there you go.

Cheers!

UPDATE

After doing some simple bench marking, with an array of 100,000 string numbers, and taking the average time from 100 iterations, it took apx 0.0072/seconds to convert the array back to ints:

//setup
$a = array_map('strval', range(0, 100000));

//get microtime as float after setup
$time = microtime(true);

//use the average of 100 conversion for consistency
$iterations = 100;

for($i=0;$i<$iterations; ++$i){
  $b = array_map('intval', $a); //set to $b so we don't convert $a on our first iteration.

  //check the first iteration, to make sure we have it setup correctly for our averaging
  if($i==0)
    echo number_format(
        ((microtime(true) - $time)),
       4
    )." \seconds\n\n";
}

echo number_format(
    ((microtime(true) - $time) / $itterations),
    4
)." \seconds\n";

Output

0.0067 \seconds
//if these are close (which they are) we have everything setup right,
//it's better to take the average for speed testing.
//and I just wanted to double check that it was being done correctly
0.0072 \seconds

Sandbox

-note- the sandbox has only 134M of Ram for PHP (i've run it out of memory on purpose to test it.. lol)

<b>Fatal error</b>:  Allowed memory size of 134217728 bytes exhausted

UPDATE1

It has been pointed out that the desired output hasn't been specified, so here is how to get all unique values:

If you want the Unique values from both arrays you can do

  $unique = array_unique(array_replace($a1,$a2));

And if the arrays are unique beforehand you can just do array_replace because you will be combining 2 unique arrays replacing any in the one array that are duplicated in the other. Therefore the result will be the unique combination of 2 unique arrays, if that makes sense.

9 Comments

@Nick in the sandbox doing an array of 100,000 string numbers, averaged over 100 conversions (for consistency) gives me a time of 0.0077 \seconds to convert the array back to ints, sandbox So it's quite fast to convert. The sandbox has only 32M of ram for PHP (I have ran it out of memory before ... lol) I used range(0,100000) and then converted it with strval to create the array, but I didn't add that into the time. :)
I remembered wrong it's 134M of memory. I run some stuff on the server at work with 3G or ram ... lol ... but the server has 64GB and that was exporting 140 million rows from the DB, doing some modifications an then writing it into a CSV.
I also benchmarked the two solutions independently. For a big array, it is much faster to convert all the values to integer first and then use the inbuilt array functions. @VdA you should accept this answer instead.
@Nick - That's somewhat surprising. And actually thinking about it you can simplify the callback in your answer that may make a difference function ($a, $b) { return $a != $b; } Loose typing will return true on this 1 == '1' and so with that we can get rid of the match and casting.
I had to delete that one, I think that sandbox is messed up .. lol .. I get different results for each one I use. Anyway It's been fun!
|
1

This is a non-issue. PHP DOES NOT require a workaround for string numbers versus non-string numbers.

Two elements are considered equal if and only if (string) $elem1 === (string) $elem2. In other words: when the string representation is the same.

Source: https://www.php.net/manual/en/function.array-diff.php

Here's my output in PHP 7.4.7. (The same output happens when I run it in PHP 5.6, and that's the earliest version I have installed right now.)

php > var_dump(array_diff([1,2,3], ["2"]));
array(2) {
  [0]=>
  int(1)
  [2]=>
  int(3)
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.