Reputation: 752
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
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
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
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