4

I would like to know how to sort numeric before string. I use array_multisort to sort my array.

There is my sample data

$arr = [
    [
        'company_name' => '',
        'expiryDate' => '2018.7',
        'classification' => 1
    ],
    [
        'company_name' => '',
        'expiryDate' => '2018.7',
        'classification' => '2-03'
    ],
    [
        'company_name' => '',
        'expiryDate' => '2018.7',
        'classification' => 3
    ],
    [
        'company_name' => '',
        'expiryDate' => '2018.7',
        'classification' => '2-01'
    ],
];

The current result after sort. The string numeric '2-01' is sort between 1 and 3

$arr = [
    [
        'company_name' => '',
        'expiryDate' => '2018.7',
        'classification' => 1
    ],
    [
        'company_name' => '',
        'expiryDate' => '2018.7',
        'classification' => '2-01'
    ],
    [
        'company_name' => '',
        'expiryDate' => '2018.7',
        'classification' => '2-03'
    ],
    [
        'company_name' => '',
        'expiryDate' => '2018.7',
        'classification' => 3
    ],
];

My expected result. I want to sort string '2-01', '2-03' after the numeric 1 and 3

$arr = [
       [
          'company_name' => '',
          'expiryDate' => '2018.7',
          'classification' => 1
       ],
       [
          'company_name' => '',
          'expiryDate' => '2018.7',
          'classification' => 3
       ],
       [
          'company_name' => '',
          'expiryDate' => '2018.7',
          'classification' => '2-01'
       ],
       [
          'company_name' => '',
          'expiryDate' => '2018.7',
          'classification' => '2-03'
       ],
    ];

My sort fields. I used array_multisort to sort multiple fields

$sortFields = [
    'classification' => SORT_ASC,
    'company_name' => SORT_ASC,
    'expiryDate' => SORT_ASC
];
6
  • Write a custom comparator with usort($arr, function($a1, $a2) {}) Commented Feb 13, 2018 at 3:58
  • 1
    What do you mean by "sort numeric before string"? Can you give an example output? Commented Feb 13, 2018 at 3:58
  • @Mike I added example output Commented Feb 13, 2018 at 4:01
  • @AniketSahrawat Could you give me some suggestion when sort multiple fields Commented Feb 13, 2018 at 4:02
  • 1
    Did you try to remove dashes(-) to dots and convert to float in classification? Commented Feb 13, 2018 at 4:03

2 Answers 2

2

Try with usort() and a comparator:

// @param $arr array that you want to sort
// @param $sortby sort by $arr[$indexOfArray][$sortby]
// @param $isDate boolean
function sortItOutYourself(&$arr, $sortby, $isDate) {
    usort($arr, function($a1, $a2) use ($sortby, $isDate) {
        if($isDate)
            return DateTime::createFromFormat("Y.m", $a1[$sortby])->getTimestamp()
                - DateTime::createFromFormat("Y.m", $a2[$sortby])->getTimestamp();

        if( (gettype($a1[$sortby]) == "string" && gettype($a2[$sortby]) == "string") ||
            (gettype($a1[$sortby]) == "integer" && gettype($a2[$sortby]) == "integer") )
            return $a1[$sortby] > $a2[$sortby] ? 1 : -1;

        return gettype($a1[$sortby]) == "integer" && gettype($a2[$sortby]) == "string" ? -1 : 1;
    });
}

sortItOutYourself($arr, "classification", false);
sortItOutYourself($arr, "company_name", false);
sortItOutYourself($arr, "expiryDate", true);
Sign up to request clarification or add additional context in comments.

9 Comments

Thank you for helping but I want to sort multiple fields , How could I do it with usor?
There are lot of examples in usort link that I have written with the answer. You can refer it for more details. You should learn to create a comparator as the very first step.
If you sort by company_name and then by classification, you will lose any sorting you did when sorting by company_name because it resorts the entire array again. You've also missed the cases where the values are equal, and you need to return 0.
Or maybe I misunderstood the question and the OP wanted to sort by those 3 things independently instead of consecutively in a single sort.
I want to sort it consecutively not independently. Therefore the answer from @AniketSahrawat is not correct , and event if I try to sort only one thing classification independently , the sort result is not correct
|
0

You can use usort() for this:

usort($arr, function($a,$b) {
    // First, sort by classification. If it returns non-zero, use this
    // sort. If not, move to the next sort type.
    $sort = sortByClassification($a['classification'],$b['classification']);
    if ($sort !== 0) {
        return $sort;
    }

    // Second, sort by company name. If it returns non-zero, use this
    // sort. If not, move to the next sort type.
    $sort = sortByCompanyName($a['company_name'],$b['company_name']);
    if ($sort !== 0) {
        return $sort;
    }

    // Third, sort by expiry date. Since this is the last sort type,
    // we can just return it
    return sortByExpiryDate($a['expiryDate'],$b['expiryDate']);
});

function sortByClassification($a,$b) {
    // Both are numeric, so sort numerically
    if (is_numeric($a) && is_numeric($b)) {
        if ($a == $b) {
            return 0;
        }
        return ($a < $b) ? -1 : 1;
    }
    // Both are strings, so sort alphabetically
    if (!is_numeric($a) && !is_numeric($b)) {
        return strcmp($a, $b);
    }
    return is_numeric($a) ? -1 : 1;
}

function sortByCompanyName($a,$b) {
    return strcmp($a, $b);
}

function sortByExpiryDate($a, $b) {
    $a_explode = explode('.', $a);
    $a_expiry = new DateTime($a_explode[0].'-'.$a_explode[1].'-1');

    $b_explode = explode('.', $b);
    $b_expiry = new DateTime($b_explode[0].'-'.$b_explode[1].'-1');

    if ($a_expiry == $b_expiry) {
        return 0;
    }
    return $a_expiry < $b_expiry ? -1 : 1;
}

print_r($arr);

Output:

Array
(
    [0] => Array
        (
            [company_name] => 
            [expiryDate] => 2018.7
            [classification] => 1
        )

    [1] => Array
        (
            [company_name] => 
            [expiryDate] => 2018.7
            [classification] => 3
        )

    [2] => Array
        (
            [company_name] => 
            [expiryDate] => 2018.7
            [classification] => 2-01
        )

    [3] => Array
        (
            [company_name] => 
            [expiryDate] => 2018.7
            [classification] => 2-03
        )

)

5 Comments

Thank you for helping but I want to sort multiple fields , How could I do it with usor?
I've updated my answer, however it's mostly untested.
Thank you for your help. I not test all these function above but the function for classification sort is correct. I will mask your answer is correct answer, but actually I like the answer is remove dash and convert it to float, it can solve my question.
How would converting it to a float solve your question when you want "2-01" to appear after "3"?
When remove dash and convert it into float. This "2-01" -> 201 therefore it larger than 3.

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.