I am having troubles to understand how array_udiff works.
According to the documentation:
array_udiff ($array1, $array2, data_compare_func)
[...] data_compare_func function must return an integer less than, equal to, or greater than zero if the first argument is considered to be respectively less than, equal to, or greater than the second.
So considering this function:
function please_compare($a, $b) {
return $a !== $b;
};
if $a equals $b, the method will return 0, 1 otherwise (because of this).
(There is no -1 returned here and I have the feeling that the explanation comes from there but I can just compare that the values are different, not that one is greater than the other one.)
Could someone explain me array_udiff's behavior in the following snippet? I also included the output of array_diff, which is actually the behavior I was expecting?
$array1 = array('a', 'b', 'c', 'd');
$array2 = array('a', 'b', 'c');
print_r(array_udiff($array1, $array2, 'please_compare'));
/* Returns:
Array
(
[0] => a
[1] => b
[3] => d
)
*/
print_r(array_diff($array1, $array2));
/* Returns:
Array
(
[3] => d
)
*/
array_udiff relies on the comparison function returning appropriate values, because it ranks the elements of your arrays. If you add some output to your comparison function, you will see that array_udiff first determines the sort order for both arrays, and only after it has done this does it start comparing array1 elements to array2 elements. By returning 1 from your comparison function, you are telling array_udiff that 'a' > 'b' and 'b' > 'a', and similarly for all other elements in both arrays. In your particular case, this causes array_udiff to think that everything in array1 > everything in array2, until it finally happens to compare the 'c' in array1 to the 'c' in array2, and gets 0 back from your function (this is why it left 'c' out of the result). See this PHP fiddle for a demonstration of the internal working of array_udiff.
Related
I have 6 users and I want to shuffle an array for each user but with a particular logic.
I have array like this:
$a = array(1, 6, 8);
When shuffled it gives me these results:
shuffle($a); //array(8,6,1) or array(8,1,6) or ...
I want to shuffle the array for a specific user and have it be the same every time for that user:
for user that has id equals 1, give array like this array(6,8,1) every time
for user that has id equals 2, give array like this array(1,8,6) every time
In other words, I want to shuffle an array with private key!
If you provide a seed to the random number generator it will randomize the same way for the same seed (see the version differences below). So use the user id as the seed:
srand(1);
shuffle($a);
Output for 7.1.0 - 7.2.4
Array
(
[0] => 1
[1] => 8
[2] => 6
)
Output for 4.3.0 - 5.6.30, 7.0.0 - 7.0.29
Array
(
[0] => 6
[1] => 1
[2] => 8
)
Note: As of PHP 7.1.0, srand() has been made an alias of mt_srand().
This Example should always produce the same result.
Quoting php.net:
This function shuffles (randomizes the order of the elements in) an array. It uses a pseudo random number generator that is not suitable for cryptographic purposes.
Whatever you are trying to get as a result, you cannot use shuffle because it will randomly give you some order.
If you want to randomly do an order to array, based on some criteria use usort:
function cmp($a, $b)
{
if ($a == $b) {
return 0;
}
return ($a < $b) ? -1 : 1;
}
$a = array(3, 2, 5, 6, 1);
usort($a, "cmp");
Now get the logic in the cmp function...
I am trying to sort an array by the length of characters in each value (and perhaps, if possible, in alphabetical order if two values have the same length of characters). For example:
Array ( [0] => this [1] => is [2] => a [3] => bunch [4] => of [5] => words;
I am trying to sort this array to look like:
Array ( [0] => a [1] => is [2] => of [3] => this [4] => bunch [5] => words;
How?
This should do it:
array_multisort(array_map('strlen', $array), $array);
Get the length of each string in an array by mapping strlen() using array_map()
Sort on the string lengths and sort the original array by the string length sorted array using array_multisort()
Looks like others have already answered but I started writing this so I'm going to post it, dang it! :)
You could take a look at usort
$data = ["this", "is", "a", "bunch", "of", "words"];
usort($data, function($a, $b) {
$difference = strlen($a) - strlen($b);
return $difference ?: strcmp($a, $b);
});
I'm using the Elvis operator ?: to just return the difference based on the string lengths if it's not 0. If it is 0, just return the return value of strcmp
You can use a custom sort function for this.
function mycmp($a, $b) {
$cmp = strlen($a) - strlen($b);
if ($cmp === 0)
$cmp = strcmp($a, $b);
return $cmp;
}
usort($array, 'mycmp');
See this:
$myarray = explode(" ", "this is a bunch of words");
usort($myarray, function($a, $b) { return strlen($a) - strlen($b) });
print_r($array);
Explanation: usort sorts in place (i.e. by reference) an array, given a custom comparator. A comparator must return a negative number if the first item should be before the second item, and a positive otherwise. A value of 0 means they are equal regarding the order.
You can add custom criteria, not related to strlen() when the lengths are the same. That's up to you and involves just an additional if block.
It is important to note that the function must define an order relationship, as in math:
criteria(a, b)>0 and criteria(b, c)>0 implies criteria(a, c)>0.
the same applies to the lower-than sign, lower-than-or-equal, greater-than-or-equal, and equal.
criteria(a, b) should have an opposite sign of criteria(b, a).
Another method:
$f = fn($s1, $s2) => strlen($s1) <=> strlen($s2);
usort($a, $f);
https://php.net/language.operators.comparison
i have two array and i want to make unique array with single array
for example i have $a=array(3); and $b=array(1,2,3) so i want $c=array(1,2,3)
i made a code like:
$a=array(3);
$b=explode(',','1,2,3');
$ab=$a+$b;
$c=array_unique ($ab);
print_r($c);
it gives me Array ( [0] => 3 [1] => 2 )
but i want to Array ( [0] => 1 [1] => 2 [2] => 3 )
$a = array(1,2,3,4,5,6);
$b = array(6,7,8,2,3);
$c = array_merge($a, $b);
$c = array_unique($c);
The operation
$ab = $a + $b
Is giving you a result you did not expect. The reason for this behaviour has been explained previously at PHP: Adding arrays together
$ab is Array ( [0] => 3 [1] => 2 [2] => 3 )
The + operator appends elements of remaining keys from the right
handed array to the left handed, whereas duplicated keys are NOT
overwritten.
array_merge provides a more intuitive behaviour.
Array merge, man. Array merge.
Anyway, as this answer for similar question ( https://stackoverflow.com/a/2811849/223668 ) tells us:
The + operator appends elements of remaining keys from the right handed array to the left handed, whereas duplicated keys are NOT overwritten.
If you have numeric keys (as in standard tables), they are for for sure duplicate in both arrays and the result is far from desired.
So the code should look like that:
$c = array_unique(array_merge($a, $b));
You need to use this array_merge to concat two array.
http://www.php.net/manual/en/function.array-merge.php
not
$ab = $a + $b
$array = array (0.1 => 'a', 0.2 => 'b');
echo count ($array);
It overwrites first array element by second, just because, I used float with 0.
And hence output of above code is 1, instead of 2.
Why PHP round array index down to 0 ?
The array keys are interpreted as numeric, but numeric keys must be integers, Therefore, both float values are cast (truncated) to integer zero and 0.2 overwrites 0.1.
var_dump($array);
array(1) {
[0]=>
string(1) "b"
}
Make the array keys strings if you want to use non integer values:
$array = array ("0.1" => 'a', "0.2" => 'b');
echo count($array);
// 2
array(2) {
["0.1"]=>
string(1) "a"
["0.2"]=>
string(1) "b"
}
Only integer is allowed as key of the array.
See what we get if I print_r($array):
Array ( [0] => b )
However you can do like this:
$array = array ('0.1' => 'a', '0.2' => 'b');
Now print_r says this:
Array ( [0.1] => a [0.2] => b )
Array indices cannot be floats. They must be either integers or strings. If you would try to var_dump($array); you would see that your array looks something like this:
array(1) {
[0]=> string(1) "b"
}
You are effectively trying to set value for key 0 twice.
You cannot use floats as numeric keys. 0.1 and 0.2 both get converted to 0
Either you have to use integers or strings. Therefore, your options are:
$array = array ('0.1' => 'a', '0.2' => 'b');
Or:
$array = array (1 => 'a', 2 => 'b');
Let's see what the PHP's own excellent manual says about arrays (emphasis mine):
The key can either be an integer or a string. The value can be of any
type.
Additionally the following key casts will occur: [...] Floats are also cast to
integers, which means that the fractional part will be truncated.
So, if you look at your array:
<?php
$array = array (0.1 => 'a', 0.2 => 'b');
var_dump($array); // let's see what actually *is* in the array
echo count ($array);
you'll get this back:
array(1) {
[0]=>
string(1) "b"
}
1
So, first your array is { 0 => 'a' }, then becomes { 0 => 'b' }. The computer did exactly what you asked it to, even if not what you intended.
Possible solution: pass the array keys as strings - there is no conversion to int, and it works as expected.
$array = array ('0.1' => 'a', '0.2' => 'b');
You must use quote on non-integer keys
$array = array ('0.1' => 'a', '0.2' => 'b');
echo count($array);
You are storing 'a' into the 0.1th element and 'b' into the 0.2nd element. This is impossible. Array indexes must be integers.
Perhaps you are wanting to use associative arrays?
$array = array ('0.1' => 'a', '0.2' => 'b');
As per the php.net document on arrays for having keys:
Additionally the following key casts will occur:
Floats are also cast to integers, which means that the fractional part
will be truncated. E.g. the key 8.7 will actually be stored under 8.
i tried dumping and interpreting the result... 0.1 and 0.2 will be interpreted as 0 and the latter overwrites the former, end result is that the array key remains 0 and value is set as b.
Hence there's nothing wrong with this behavior.
its because floats are casted to integers, so the second entry overwrites the first.
Actually you are doing this:
$array = array (0 => 'a', 0 => 'b');
echo count ($array);
Php.net Array:
"Floats are also cast to integers, which means that the fractional part will be truncated. E.g. the key 8.7 will actually be stored under 8."
I have a key => value array:
a => 2
c => 1
b => 3
I tried this:
ksort($result);
arsort($result);
But it doesn't work. I'm trying to sort by key alphabetically a-z and then sort it by value ascending 0-infinity.
so I should get
c => 1
a => 2
b => 3
But those sorts didn't give me what I wanted.
Try using asort() instead of arsort(). arsort() will sort the array in reverse order. Something like this should "work":
$test = array(
'a' => 0,
'b' => 1,
'c' => 2
);
ksort($test);
asort($test);
Mario is correct that this won't work if multiple items contain the same value. Alternatively, you could use uksort() which allows you to define exactly how the array is sorted. For example you could sort two items using their values by default. But if the values are the same sort by their keys.
$test = array(
'a' => 2,
'd' => 1,
'c' => 1,
'b' => 3
);
function cmp($a, $b){
global $test;
$val_a = $test[$a];
$val_b = $test[$b];
if($val_a == $val_b){
return ($a < $b) ? -1 : 1;
}
return ($val_a < $val_b) ? -1 : 1;
}
uksort($test, 'cmp');
I get unexpected results because sorting values that have the same value is unstable.
So what you forgot to mention in your question is that values can occur twice, and you want arrays sorted by values and keys secondarily.
c => 1
a => 2
z => 2
b => 3
There's no function for that in PHP. You could however try to sort by keys first ksort(), and then apply a user-defined function for sorting by value uasort(). In the callback it's important to also implement the $a == $b check and return 0. So the previous key-ordering might not be accidentally altered by +1 or -1 comparison states. (Don't know if that actually works.)
Otherwise you'll have to implement the whole sorting algorithm yourself, possibly separating keys and values in distinct maps.