0

How to sort an array at PHP to force selected row as a first ?

My array is

array[]=array(id=>'a', content=>'lemon');
array[]=array(id=>'b', content=>'apple');
array[]=array(id=>'c', content=>'banana');
array[]=array(id=>'d', content=>'cherry');

How to sort the array to force

array[]=array(id=>'b', content=>'apple');

as a first row and doesn't matter the rest (apple is the key).

And in other example turn sort to get

array[]=array(id=>'d', content=>'cherry');

as a first row and doesn't matter the rest (cherry is the key).

uxmal
  • 428
  • 1
  • 7
  • 17
  • What are the other rows sorted by (is it the id, content or the whole array)? – Nigel Ren May 26 '19 at 06:54
  • I'd use `array_splice` to remove the selected element from the array. Then use `array_unshift` to prepend the removed element to the beginning of the array. – Ultimater May 26 '19 at 06:56
  • The order of other rows doesn't have a sort rule - you can add every next row to array, and force your selected as a first – uxmal May 26 '19 at 07:03

3 Answers3

2

There are 2 ways I can think of doing this. The first is as Ultimater in the comments suggest to extract the matching row, then sort and then add the row back in...

$first = 'apple';
$array = [];
$array[]=array('id'=>'a', 'content'=>'lemon');
$array[]=array('id'=>'b', 'content'=>'apple');
$array[]=array('id'=>'c', 'content'=>'banana');
$array[]=array('id'=>'d', 'content'=>'chery');
$firstElement = array_search($first, array_column($array, "content"));
$row = $array[$firstElement];
unset($array[$firstElement]);
sort($array);
array_unshift($array, $row);
print_r($array);

The second is to use usort and add specific clauses in that if the key matches the row you want first, then it will always force it to the first row...

$first = 'apple';
usort($array, function ($a, $b) use ($first){
    if ( $a['content'] == $first)   {
        return -1;
    }
    if ( $b['content'] == $first)   {
        return 1;
    }
    return $a <=> $b;
});
print_r($array);

(I've used <=> in this which is PHP 7+, there are alternatives if you need to use PHP 5).

If as your comment suggests that there is no need to sort the rest of the data, then the first set of code minus the sort() should do.

Nigel Ren
  • 56,122
  • 11
  • 43
  • 55
  • If we're not sorting by anything else, I think simply `return ($b['content'] == $first);` will work for the usort. – Don't Panic May 26 '19 at 07:09
  • @Don'tPanic my last bit (added after the OP's comment was posted) is probably the best - if you don't need to sort it - then don't. Just extract the row and add it to the front. – Nigel Ren May 26 '19 at 07:11
  • I agree, this isn't really a sort problem, unless there are multiple apples/cherries/whatever that need to be moved to the top, but it doesn't sound like that's the case. – Don't Panic May 26 '19 at 07:16
2

Another way to do this is to effectively rotate the array using array_slice, bringing the element you want to the start:

$first = 'apple';
$k = array_search($first, array_column($array, 'content'));
$array = array_merge(array_slice($array, $k), array_slice($array, 0, $k));
print_r($array);

Output:

Array (
  [0] => Array ( [id] => b [content] => apple )
  [1] => Array ( [id] => c [content] => banana )
  [2] => Array ( [id] => d [content] => cherry )
  [3] => Array ( [id] => a [content] => lemon ) 
)

Demo on 3v4l.org

Nick
  • 138,499
  • 22
  • 57
  • 95
0

One other option - if id:content is one to one, we can index the array by content and merge with an array with a single empty "apple" key (or whichever content value you're looking for).

$array = array_merge(['apple' => []], array_column($array, null, 'content'));

If the resulting string keys are undesirable the array can be reindexed with array_values.

If the array only contains id and content and id:content is in fact one to one, a "dictionary" of key-value pairs will be handier to deal with than a list of rows like this and it would probably be better to set the array up that way to begin with if possible.

If id:content is not one to one, then... never mind. ;-)

Don't Panic
  • 41,125
  • 10
  • 61
  • 80