Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Move array element with a particular value to top of array

Tags:

php

I have an array that looks similar to this:

Array
(
  [0] => stdClass Object
    (
      [Leasing] => 12939.74
      [Name] => Jeremy
      [Rental] => 0
      [Sales] => 56603.13
      [Total] => 69542.87
    )
  [1] => stdClass Object
    (
      [Leasing] => 0
      [Name] => Shaun
      [Rental] => 0
      [Sales] => 58590
      [Total] => 58590
    )
  [2] => stdClass Object
    (
      [Leasing] => 0
      [Name] => Lindsay
      [Rental] => 0
      [Sales] => 22951.97
      [Total] => 22951.97
    )
  [3] => stdClass Object
    (
      [Leasing] => 0
      [Name] => Sally
      [Rental] => 1200
      [Sales] => 21624.9
      [Total] => 22824.9
    )
  [4] => stdClass Object
    (
      [Leasing] => 0
      [Name] => House
      [Rental] => 0
      [Sales] => 16235.81
      [Total] => 16235.81
    )
  [5] => stdClass Object
    (
      [Leasing] => 5298.85
      [Name] => Bill
      [Rental] => 1200
      [Sales] => 0
      [Total] => 6498.85
    )
)

Currently, the array is sorted by total using this:

usort($data, function ($a, $b) {
    return $b->Total - $a->Total;
});

Now, I need to be able to ALWAYS have the person with [Name] => House to the top of the array. My thoughts are that I can leave it sorted by Total (because I still need it that way) and then take the element with the House value and put it at the start of the array. I can take a particular KEY and put it at the top, but the KEY's may change depending on who has the highest total. How can I always put the person named House at the top of the array?

like image 287
mdance Avatar asked Dec 12 '22 18:12

mdance


2 Answers

This should work:

usort($data, function ($a, $b) {
    if ($a->Name != "House" && $b->Name == "House") {
        return 1;
    } elseif ($a->Name == "House" && $b->Name != "House") {
        return -1;
    } else {
        return $b->Total - $a->Total;
    }
});

From PHP: usort - Manual:

The comparison 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.

In this case, return 1 tells the sorting function that House is greater than any other value, and -1 that House is lesser than any other value.

like image 112
Tchoupi Avatar answered Feb 20 '23 01:02

Tchoupi


Your requirements:

  1. Sort by the Name column -- position House valued rows before non-House valued rows.
  2. Sort by the Total column DESC.

From PHP7, the spaceship operator (<=>) makes the scripting the sorting rules very clean by evaluating arrays of rules (reading the elements from left to right).

To sort House rows first, evaluate each object's Name string to be identical to House. false evaluations will be treated as 0 and true evaluations will be treated as 1. By writing the $b data on the left side of the operator, descending sorting is implemented. The House object will be the only object to evaluate as true, and because it is the first sorting condition, it will take priority as the first object in the array of objects.

For the other objects that that do not contain House, the second sorting condition is evaluated. By writing $b's Total value on the left side and the $a's Total values on the right side, descending sorting is again used -- this puts objects with higher totals before objects with lower totals.

Code: (Demo)

usort(
    $objects,
    fn($a, $b) =>
         [$b->Name === 'House', $b->Total]
         <=>
         [$a->Name === 'House', $a->Total]
);

For completeness, you can also use array_multisort() but it will be less efficient than usort() in this case because multiple function calls will be necessary to prepare the sorting columns. (Demo)

array_multisort(
    array_map(fn($obj) => $obj->Name !== 'House', $objects), // ASC puts falses before trues
    array_column($objects, 'Total'),
    SORT_DESC,
    $objects
);
like image 37
mickmackusa Avatar answered Feb 20 '23 02:02

mickmackusa