Asked  2 Years ago    Answers:  5   Viewed   215 times

I'm currently trying to sort a multidimensional array by its subvalues. The structure of the array is:

[0] => Array
    (
        [id] => 87
        [sold] => 50
        [stock] => 991
        [speed] => 1.5
        [days_left] => 660.66666666667
    )

[1] => Array
    (
        [id] => 97
        [sold] => 20
        [stock] => 120
        [speed] => 1.2
        [days_left] => 100
    )

[2] => Array
    (
        [id] => 36
        [sold] => 2
        [stock] => 1020
        [speed] => 1.02
        [days_left] => 1000
    )

The code I'm using is:

usort($data, function($a, $b) { return $a[$_GET['sortby']] - $b[$_GET['sortby']]; });

where the $_GET['sortby'] variable equals the key.

So far so good, everthing is working, it sorts all values correctly EXCEPT the speed! First, I thought it has something to do with the decimal numbers, but the days_left include also decimals and are sorted correctly.. :/

Correct output (days_left):

[0] => Array
    (
        [id] => 97
        [sold] => 20
        [stock] => 120
        [speed] => 1.2
        [days_left] => 100
    )

[1] => Array
    (
        [id] => 87
        [sold] => 50
        [stock] => 991
        [speed] => 1.5
        [days_left] => 660.66666666667
    )

[2] => Array
    (
        [id] => 36
        [sold] => 2
        [stock] => 1020
        [speed] => 1.02
        [days_left] => 1000
    )

Wrong output (speed):

[0] => Array
    (
        [id] => 97
        [sold] => 20
        [stock] => 120
        [speed] => 1.2
        [days_left] => 100
    )

[1] => Array
    (
        [id] => 87
        [sold] => 50
        [stock] => 991
        [speed] => 1.5
        [days_left] => 660.66666666667
    )

[2] => Array
    (
        [id] => 36
        [sold] => 2
        [stock] => 1020
        [speed] => 1.02
        [days_left] => 1000
    )

Hope anybody can help me!

 Answers

3

See usort docs. Float result will be converted to integer. For correct work use this code:

usort(
    $data, 
    function($a, $b) {
        $result = 0;
        if ($a[$_GET['sortby']] > $b[$_GET['sortby']]) {
            $result = 1;
        } else if ($a[$_GET['sortby']] < $b[$_GET['sortby']]) {
            $result = -1;
        }
        return $result; 
    }
);
Friday, November 4, 2022
4

I've used a few things here, the main thing is that I use the sorting array as a target for an array_replace() and I use array_column() to index the objects by (this needs PHP 7.0+ to work with objects)...

$input = array_column($inputArray, null, "id");   
$sort = array_fill_keys($sortingArray, null);
$output = array_filter(array_replace($sort, $input));

The array_filter() will remove any elements which aren't in the input array but in the sorting array. The array_fill_keys() is used instead of array_flip() so that I can set a null value, which allows the filter to work.

Monday, October 3, 2022
5

I'm not familiar enough with the Decimal class to help you out, but your problem is due to the fact that decimal fractions can often not be accurate represented in binary, so what you're seeing is the closest possible approximation; there's no way to avoid this problem without using a special class (like Decimal, probably).

EDIT: What about the decimal class isn't working properly for you? As long as I start with a string, rather than a float, powers seem to work fine.

>>> import decimal
>>> print(decimal.Decimal("1.2") ** 2)
1.44

The module documentation explains the need for and usage of decimal.Decimal pretty clearly, you should check it out if you haven't yet.

Thursday, October 6, 2022
5

here an array_multisort example:

foreach ($array as $key => $node) {
   $timestamps[$key]    = $node[2];
}
array_multisort($timestamps, SORT_ASC, $array);
Tuesday, November 1, 2022
1

String.format might help you out here - NumberFormat

  private static void printfWithLocale(Locale locale, Double d){
    System.out.println("Output locale: " + locale.toString());
    String simpleOutputTeplate = "simpleOutputTeplate: %s";
    String refinedOutputTeplate = "refinedOutputTeplate: %.10f";

    System.out.println(String.format(locale, simpleOutputTeplate, d));
    System.out.println(String.format(locale, refinedOutputTeplate, d));

  }

  public static void main(String[] args) {

    Double d = new Double(3.1234567890123456789);

    printfWithLocale(Locale.US, d);
    System.out.println("");
    printfWithLocale(Locale.FRANCE, d);
  }

Code output:

Output locale: en_US
simpleOutputTeplate: 3.1234567890123457
refinedOutputTeplate: 3.1234567890

Output locale: fr_FR
simpleOutputTeplate: 3.1234567890123457
refinedOutputTeplate: 3,1234567890

You will notice that the %s (string) does not conform to the Locale, but does format the Double up to 17 decimal points. With String.format you can further refine the way your numbers are formatted in a string.

Sunday, August 21, 2022
 
Only authorized users can answer the search term. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :
 

Browse Other Code Languages