usort multisort array based on another array

扶醉桌前 提交于 2021-02-15 07:36:46

问题


I have array that I need to sort by another array form 2 fields zip code and approve

I am able to sort it by zip code but unable to do it with approved field so for eg

I need to sort by 60007,60001,60003,60002 (as per sortlike order) all zip code from 60007 and approved should come first so

$sortLike=array(60007,60001,60003,60002);
$array1= array(
    array ('ID' => 138,'zip_code' => 60007,'approved' => 1),
    array('ID' => 103,'zip_code' => 60007,'approved' => 0),
    array('ID' => 114,'zip_code' => 60007,'approved' => 1),
    array('ID' => 105,'zip_code' => 60003,'approved' => 0),
    array('ID' => 124,'zip_code' => 60002,'approved' => 0)
)

so 60007 and aproved should come first than 60007 with 0(unapproved) and than all 60001 approved than all 60001 unapproved(and so on as per $sortlike) here is complete php code

<?php
$array1= array(
    array ('ID' => 138,'zip_code' => 60007,'approved' => 1),
    array('ID' => 103,'zip_code' => 60007,'approved' => 0),
    array('ID' => 114,'zip_code' => 60007,'approved' => 1),
    array('ID' => 105,'zip_code' => 60003,'approved' => 0),
    array('ID' => 124,'zip_code' => 60002,'approved' => 0),
    array('ID' => 104,'zip_code' => 60002,'approved' => 1),
    array('ID' => 106,'zip_code' => 60001,'approved' => 0),
    array('ID' => 188,'zip_code' => 60022,'approved' => 0),
    array('ID' => 184,'zip_code' => 60022,'approved' => 1),
);
function sort_results ($a, $b) {
   $sortLike=array(60007,60001,60003,60002);
   if (!in_array ($a['zip_code'], $sortLike)) { return 1; } // Push unknown values at the end of the array
   return array_search($a['zip_code'], $sortLike) > array_search($b['zip_code'], $sortLike);
}

usort ($array1, 'sort_results');
echo "<pre>";
print_r($array1);
echo "</pre>";

回答1:


I guess you're asking how you can also sort by 'approved', because that is currently missing in your code.

The solution to this question is to define an order in which the keys of your input array $array1 are checked.

So you need to check zip_code at first. If you get a result != 0, you can return immediately. But if the result is == 0 (the zip codes are equal) you need to check the second key ('approved' in your case).

$array1= array(
    array ('ID' => 138,'zip_code' => 60007,'approved' => 1),
    array('ID' => 103,'zip_code' => 60007,'approved' => 0),
    array('ID' => 114,'zip_code' => 60007,'approved' => 1),
    array('ID' => 105,'zip_code' => 60003,'approved' => 0),
    array('ID' => 124,'zip_code' => 60002,'approved' => 0),
    array('ID' => 104,'zip_code' => 60002,'approved' => 1),
    array('ID' => 106,'zip_code' => 60001,'approved' => 0),
    array('ID' => 188,'zip_code' => 60022,'approved' => 0),
    array('ID' => 184,'zip_code' => 60022,'approved' => 1),
);
function sort_results ($a, $b) {
    $sortLike=array(60007,60001,60003,60002);
    if (!in_array ($a['zip_code'], $sortLike)) { return 1; } // Push unknown values at the end of the array
    $zip_res = array_search($a['zip_code'], $sortLike) - array_search($b['zip_code'], $sortLike); // check zip_code order 
    if($zip_res == 0){ // if the zip_codes are equal
        $zip_res = $b['approved'] - $a['approved']; // sort by the 'approved' key
    }
    return $zip_res;
}

//edit

You can use a lamda function to move $sortLike out of the function like this (requires PHP >= 5.3):

$sortLike=array(60007,60001,60003,60002);
$sort_results = function ($a, $b) use ($sortLike){ // create lambda function with "use" keyword
    if (!in_array ($a['zip_code'], $sortLike)) { return 1; } // Push unknown values at the end of the array
    $zip_res = array_search($a['zip_code'], $sortLike) - array_search($b['zip_code'], $sortLike);
    if($zip_res == 0){
        $zip_res = $b['approved'] - $a['approved'];
    }
    return $zip_res;
};

usort ($array1,$sort_results); // pass lambda function in
echo "<pre>";
print_r($array1);
echo "</pre>";
die();



回答2:


usort($array_data, array($sort_obj = new cmpArray('array_key'), "cmp__"));
class cmpArray
     {

         var $key;

         function __construct($key)
         {
             $this->key = $key;
         }

         function cmp__($a, $b)
         {
             $key = $this->key;
             if($a[$key] == $b[$key])
                 return 0;

             return (($a[$key] > $b[$key]) ? 1 : -1);
         }

     }



回答3:


<?php
$array1= array(
array ('ID' => 138,'zip_code' => 60007,'approved' => 1),
array('ID' => 103,'zip_code' => 60007,'approved' => 0),
array('ID' => 114,'zip_code' => 60007,'approved' => 1),
array('ID' => 105,'zip_code' => 60003,'approved' => 0),
array('ID' => 124,'zip_code' => 60002,'approved' => 0),
array('ID' => 104,'zip_code' => 60002,'approved' => 1),
array('ID' => 106,'zip_code' => 60001,'approved' => 0),
array('ID' => 188,'zip_code' => 60022,'approved' => 0),
array('ID' => 184,'zip_code' => 60022,'approved' => 1),
);

function sort_it ($a) {
$sortedarr = array();
$sortLike=array(60007,60001,60003,60002);
foreach($sortLike as $el){
    array_push($sortedarr,getElements($a,$el));
}
}



function getElements($arr,$e){
$newarr = array();
foreach($arr as $val){
    if($val['approved'] == '1' && $val['zip_code'] == $e){
    $newarr[] = $val;
    }
}
foreach($arr as $val){
    if($val['approved'] == '0' && $val['zip_code'] == $e){
    $newarr[] = $val;
    }
}
return $newarr;
}

$array2 = sort_it($array1);
echo "<pre>";
print_r($array1);
echo "</pre>";
echo "<pre>";
print_r($array2);
echo "</pre>";
?>



回答4:


usort() PHP < v7.4: (Demo)

$priorityZips = array_flip([60007, 60001, 60003, 60002]);
$priorityCount = count($priorityZips);

usort($rows, function($a, $b) use ($priorityZips, $priorityCount) {
    return [
               $priorityZips[$a['zip_code']] ?? $priorityCount,
               $a['zip_code'],
               $b['approved']
           ]
           <=>
           [
               $priorityZips[$b['zip_code']] ?? $priorityCount,
               $b['zip_code'],
               $a['approved']
           ];
});

usort() PHP >= v7.4: (Demo)

$priorityZips = array_flip([60007, 60001, 60003, 60002]);
$priorityCount = count($priorityZips);

usort($rows, fn($a, $b) =>
    [
        $priorityZips[$a['zip_code']] ?? $priorityCount,
        $a['zip_code'],
        $b['approved']
    ]
    <=>
    [
        $priorityZips[$b['zip_code']] ?? $priorityCount,
        $b['zip_code'],
        $a['approved']
    ]
);

array_multisort() PHP < v7.4: (Demo)

$priorityZips = array_flip([60007, 60001, 60003, 60002]);
$priorityCount = count($priorityZips);

array_multisort(
    array_map(
        function($row) use ($priorityZips, $priorityCount) {
            return $priorityZips[$row['zip_code']] ?? $priorityCount;
        },
        $rows
    ),
    array_column($rows, 'zip_code'),
    array_column($rows, 'approved'),
    SORT_DESC,
    $rows
);

array_multisort() PHP >= v7.4: (Demo)

$priorityZips = array_flip([60007, 60001, 60003, 60002]);
$priorityCount = count($priorityZips);

array_multisort(
    array_map(
        fn($row) => $priorityZips[$row['zip_code']] ?? $priorityCount,
        $rows
    ),
    array_column($rows, 'zip_code'),
    array_column($rows, 'approved'),
    SORT_DESC,
    $rows
);

In my snippets above, I refer to your input array to be sorted as $rows.

This task can be performed several ways, but I've shown a few that I feel are cleanest / most readable. If performance is critical in your application, I'll encourage you to benchmark using your own real data; otherwise choose the snippet that you are most comfortable maintaining long-term.

In PHP versions below 7.4, passing variables into custom function scopes is done using use(). In PHP7.4 and higher, "arrow function syntax", strips away a fair chunk of syntax in the custom function and allows the entry of variables without use().

The "spaceship operator" / "three-way comparison operator" (<=>) makes building multi-criteria sorting MUCH cleaner and concise versus a bunch of condition blocks. The spaceship operator will synchronously process the elements in the arrays and return the correctly evaluated -1, 0, or 1. It will also treat numeric strings as numbers.

I flipped the lookup array of prioritized zipcodes to enable the "null coalescing operator" (??) to swiftly return the priority value or else default to a number greater than the highest integer value in the lookup.

Regarding the structure of the usort arrays being compared, you may like to see this answer that goes into a bit more detail.



来源:https://stackoverflow.com/questions/25603313/usort-multisort-array-based-on-another-array

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!