Steve Smith
Steve Smith

Reputation: 752

Sort database result set by earliest position of a column value

I have an array pulled back from a database that is ordered by number ([0]=>'',[1]=>''...etc) within each element there are various associative values (title,date,area...etc). I need the array reordering so that all the elements with the same 'area' variable appear together. So effectively we will still have a ([0]=>'',[1]=>''...etc) array but the first 5 or so will have the same 'area' then the next however many will have the same 'area' and so on.

To make it easier there are 4 possible values for the 'area' field (north,west,central,blyth valley).

What I don't want is a multi-dimensional array grouped by the 4 areas, I need it as one long array just in the order that puts all 'like' areas together.

Upvotes: 0

Views: 141

Answers (3)

mickmackusa
mickmackusa

Reputation: 47864

If you don't care about the actual order of the areas and purely wish to group like-area data together, temporarily group the rows by data. This will make an array with 3 levels of depth. To return the data set to 2 levels, spread the grouped data inside of an array_merge() call. Demo

$array = [
    ['id' => 1, 'area' => 'west'],
    ['id' => 2, 'area' => 'blyth valley'],
    ['id' => 3, 'area' => 'north'],
    ['id' => 4, 'area' => 'west'],
    ['id' => 5, 'area' => 'central'],
    ['id' => 6, 'area' => 'west'],
    ['id' => 7, 'area' => 'north'],
];

$groups = [];
foreach ($array as $row) {
    $groups[$row['area']][] = $row;
}
var_export(
    array_merge(
        ...array_values($groups)
    )
);

Output:

array (
  0 => 
  array (
    'id' => 1,
    'area' => 'west',
  ),
  1 => 
  array (
    'id' => 4,
    'area' => 'west',
  ),
  2 => 
  array (
    'id' => 6,
    'area' => 'west',
  ),
  3 => 
  array (
    'id' => 2,
    'area' => 'blyth valley',
  ),
  4 => 
  array (
    'id' => 3,
    'area' => 'north',
  ),
  5 => 
  array (
    'id' => 7,
    'area' => 'north',
  ),
  6 => 
  array (
    'id' => 5,
    'area' => 'central',
  ),
)

Upvotes: 0

smilly92
smilly92

Reputation: 2443

Here is a solution...

$arr = array(
    '0' => array( 'area' => 'west' ),
    '2' => array( 'area' => 'north' ),
    '3' => array( 'area' => 'west' ),
    '4' => array( 'area' => 'central' ),
    '5' => array( 'area' => 'west' ),
    '6' => array( 'area' => 'north' )
);

$new = array();

// Get a list of possible areas
$areas = array();
foreach ($arr as $key => $value) {
    if ( ! in_array( $value['area'] , $areas ) ) {
        array_push( $areas, $value['area'] );
    }
}

// For each area...
foreach ($areas as $key => $area) {
    // Find a area that matches...
    foreach ($arr as $key => $value) {
        if ( $value['area'] == $area ) {
            array_push( $new, $value );
        }
    }
}

Also you may want to remove the first loop if there are only a set number of areas. Just fill the areas array with a list of possible areas in the order you want.

Upvotes: 1

MatsLindh
MatsLindh

Reputation: 52792

Simply sort the array using a custom sort function with usort if you're unable to ORDER BY the field in SQL. Shouldn't be too much of a performance hit anyway, depending on the number of entries you have in the array.

usort($posts, function ($a, $b) { return strcmp($a['area'], $b['area']); });

If you want a predetermined sort order, add a list of the different areas and their priorities:

$sortOrder = array(
    'north' => 100,
    'west' => 200,
    'central' => 300,
    'blyth valley' => 400,
);

usort($posts, function ($a, $b) use ($sortOrder) {
    if (isset($sortOrder[$a['area']], $sortOrder[$b['area']]))
    {
        return $b['area'] - $a['area'];
    }

    if (isset($sortOrder[$a['area']]))
    {
        return -1;
    }

    if (isset($sortOrder[$b['area']]))
    {
        return 1;
    }

    return 0;
});

You can remove the tests if you have a priority defined for all possible values of the 'area' field, although I'd suggest leaving it in since you'll probably be changing the possible values in the future.

Upvotes: 1

Related Questions