Why does the array_reduce() method work differently when adding and multiplying? When I add the array values below, the code produces the expected result: 15. But when I multiply, it returns: 0. Same code... The only difference is that the + sign is switched for the * sign.
function sum($arr){
print_r(array_reduce($arr, function($a, $b){return $a + $b;}));
}
function multiply($arr){
print_r(array_reduce($arr, function($a, $b){return $a * $b;}));
}
sum(array(1, 2, 3, 4, 5)); // 15
multiply(array(1, 2, 3, 4, 5)); // 0
According to documentation, you might wanna try
function multiply($arr){
print_r(array_reduce($arr, function($a, $b){return $a * $b;},1));
}
Here is a quote from this discussion:
The first parameter to the callback is an accumulator where the result-in-progress is effectively assembled. If you supply an $initial value the accumulator starts out with that value, otherwise it starts out null.
Related
I need to modify an array of objects, based on a "custom_sorting" value. I use usort like this:
usort($this->rows, function($a, $b) {
return $a->custom_sorting <=> $b->custom_sorting;
});
However, the returned sort order is a bit off, as can be seen in the example order below. Notice 4 comes after 39, so it treats 4 as a higher value than 39. Same goes for 5,6,7,8,9 - all treated as higher values than 45. What can I do to sort it in the correct numeric order?
5-37
5-38
5-39
5-4
5-40
5-41
5-42
5-43
5-44
5-45
5-5
5-7
5-8
5-9
Thanks
As #Nigel Ren's comment suggests, your custom_sorting is probably based on string, so it's working as it should. Instead try:
Newer answer using the built in strnatcmp:
usort($this->rows, function($a, $b) {
return strnatcmp($a->custom_sorting, $b->custom_sorting);
});
Older, more manual answer:
usort($this->rows, function($a, $b) {
$aDash = strpos($a->custom_sorting, '-');
$bDash = strpos($b->custom_sorting, '-');
$compareFirstPart = ((int) substr($a->custom_sorting, 0, $aDash-1)) <=> ((int) substr($b->custom_sorting, 0, $bDash-1));
if ($compareFirstPart !== 0) {
return $compareFirstPart;
}
return ((int) substr($a->custom_sorting, $aDash)) <=> ((int) substr($b->custom_sorting, $bDash));
});
Explanation:
Take the parts before the dash ('-'), cast them to ints, and comare them as ints.
If they are equal the result is 0, so return the result for the same comparison with the part after the dash;
I have two multidimensional arrays, each element in the array consists of 2 elements, the first is a string and the second is an integer. I want to get the difference between the two multidimensional arrays based on the second value if and only if the first elements are equal. I am using array_udiff such as below:
$arrdiff = array_udiff($arr1, $arr2, 'udiffCompare');
I implemented the function array_udiff such that if the first element is different to return them as equal since I don't want it to appear in the difference, and if the first element is equal then compare the second element and return accordingly, below is the function I implemented
function udiffCompare($a, $b) {
return strcmp($a[0], $b[0]) == 0 ? $ a[1] - $b[1] : 0;
}
However, even though I have two arrays with the same first element but a different second element, they are not returned in the result of array_udiff function.
Am I missing anything here? Any help is appreciated.
The problem is, you're looking for a difference within an intersection, using only a difference function.
Try computing the intersection based on the string value, and using the result to compute the difference based on the int value.
function sameString ($a, $b) {
return strcmp($a[0], $b[0]);
}
function differentInt($a, $b) {
return $a[1] - $b[1];
}
$diff = array_udiff(array_uintersect($arr1, $arr2, 'sameString'), $arr2, 'differentInt');
This is the Example #1 from the php.net usort() page:
<?php
function cmp($a, $b) {
if ($a == $b) {
return 0;
}
return ($a < $b) ? -1 : 1;
}
$a = array(3, 2, 5, 6, 1);
usort($a, "cmp");
foreach ($a as $key => $value) {
echo "$key: $value\n";
}
?>
The usort function takes the values within the array as pairs ($a-$b; so this is - 3-2, 2-5, 5-6, 6-1) and moves the $b value depending on whether the cmp() function returns -1, 0 or 1. If it is -1 the $b gets moved down (within a current pair), if it is 0 it stays in the same place and if it is 1 it gets moved up. This is how this is suppose to be working based on the top comment from the php.net manual usort() page.
Is there any way to see how this works step by step (the sorting process)? Am I able to see it or is it only possible to see the final result after the sorting is done? I want to understand fully how this process works.
Using some debug output in your comparison function you can only see the comparisons that PHP does, but can't see intermediate states of the array.
But the algorithm used in usort is well known - it's QuickSort ( Which sort algorithms does PHP's usort apply? ).
You can see its vizualisation at http://www.algomation.com/algorithm/quick-sort-visualization (or just google "quicksort algorithm visualization")
I got a array like this:
$json = '{"Categorie1":[{"created":"2017-07-17 08:53:00","catid":"54"},{"created":"2017-05-23 10:15:00","catid":"54"},{"created":"2017-05-09 05:49:23","catid":"54"}],"Categorie2":[{"created":"2017-03-21 08:58:37","catid":"59"},{"created":"2016-12-23 12:48:00","catid":"59"},{"created":"2016-12-08 09:57:10","catid":"59"}],"Categorie3":[],"Categorie4":[{"created":"2017-08-02 07:15:07","catid":"70"},{"created":"2017-08-01 08:03:00","catid":"70"},{"created":"2017-07-31 09:25:00","catid":"70"}],"Categorie5":[{"created":"2017-07-26 14:09:00","catid":"74"},{"created":"2017-06-29 14:03:00","catid":"74"},{"created":"2017-06-28 06:35:35","catid":"74"}]}';
And I wrote a sorting function. Basically it checks which block (categorie) got the newest entry and brings that block to top, sort the blocks):
$array = json_decode($json, true);
function custom($a, $b) {
foreach($a as $k => $v) {
if (isset($b[$k])) {
return (strtotime($a[$k]["created"]) <= strtotime($b[$k]["created"]));
}
}
}
uasort($array, "custom");
When I print this with PHP 5 its perfect: Categorie4 is the first block". But with PHP 7 it doesn't.
print("<pre>");
print_r($array); // PHP 5 is as expected, php 7 is not
I know there where changes, but I can't figure out how to change my code.
Can you guys helping me change the code? The result should show categorie4 as first cat...
The callback function used by the user-defined array sorting functions must return an integer value that is <0 if $a < $b, 0 when $a == $b or >0 when $a > $b. Yours return a boolean that is converted to 1 or 0 and that doesn't reflect the correct order of $a and $b.
It's not clear from the question how should be sorted the empty entries (Categorie3) and I think their place is at the end.
Try this code for PHP 5:
uasort($array, function (array $a, array $b) {
if (empty($a)) { return +1; } // empty arrays go to the end of the list
if (empty($b)) { return -1; }
return strcmp($a[0]['created'], $b[0]['created']);
});
The date&time values of created use a format that can be sorted directly as strings, there is no need to convert them to timestamps.
In PHP 7 you can use the new <=> comparison operator that, in theory, should run faster than the strcmp() function while it produces the same result.
uasort($array, function (array $a, array $b) {
if (empty($a)) { return +1; } // empty arrays go to the end of the list
if (empty($b)) { return -1; }
return $b[0]['created'] <=> $a[0]['created'];
});
I have 2 variables each containing a number (integer). I would like to sort them to have the lowest number first and the second largest. For example:
$sortedVar = getSmaller(45, 62); // Will return 45
$sortedVar = getSmaller(87, 23); // Will return 23
Do you see what I want to do? Can you help me please?
Thanks :)
http://php.net/manual/en/function.min.php
min — Find lowest value..
If the first and only parameter is an array, min() returns the lowest value in that array. If at least two parameters are provided, min() returns the smallest of these values.
Note:
Values of different types will be compared using the standard comparison rules. For instance, a non-numeric string will be compared to an integer as though it were 0, but multiple non-numeric string values will be compared alphanumerically. The actual value returned will be of the original type with no conversion applied.
Caution
Be careful when passing arguments with mixed types values because min() can produce unpredictable results...
Use min() which supports any number of arguments as well as arrays.
$smallest = min(1,2); //returns 1
$smallest = min(4,3,2); //returns 2
$smallest = min(array(5,4)) //returns 4
function getSmaller($a, $b) {
return $a < $b ? $a : $b;
}
In plain english, if $a is smaller than $b, then return $a, else return $b.
Or as others pointed out, there's also a function for that, called min().
$sortedVar = $a < $b ? $a : $b;