jej07
asked on
Help needed grouping and sorting an array
I tried Googling but can't seem to find the answer or a similar technique that will help solve my problem. I'm not even really sure how to best to accomplish this.
What I'm trying to do group the results from my $distance_array, based on the key [type] from my $curr_res array, Then each group would be ordered by the $distance_array value.
The key [type] has three possible values Retail Store, Drop off, Contractor. However, I want to customize the order, rather than sorting by ascending or descending.
So the final output should look similar to this...
Drop off
Company One
2 Miles
Drop off
Company Two
5 Miles
Retail Store
Company Three
1.5 Miles
Contractor
Company Four
7 Miles
Contractor
Company Five
10 Miles
I'm looping through the $distance_array like this.
And my arrays look like this.
$distance_array
Array ( [10066] => 5.3109370772026 [10347] => 8.8816963223926 [66] => 12.837831771854 [10483] => 12.878820381449 [10625] => 15.002565483354 [64] => 15.29246611189 [10438] => 15.388386254936 [10327] => 19.261218858628 [10461] => 22.650257356203 [10243] => 26.26616586252 [10246] => 32.440312706073 [10422] => 45.859312064584 [10529] => 61.744883818327 [10397] => 67.358673239898 [10632] => 67.437024249966 [10547] => 74.253276511624 [10572] => 74.93732142815 [10240] => 97.381361623479 )
$curr_res
Array ( [id] => 10066 [type] => Retail Store [company_name] => Joe's Place [address] => Joes Address [city] => Madison [state] => WI [zip] => 53718 [country] => United States [lat] => 43.011803 [lng] => -89.513130 )
What I'm trying to do group the results from my $distance_array, based on the key [type] from my $curr_res array, Then each group would be ordered by the $distance_array value.
The key [type] has three possible values Retail Store, Drop off, Contractor. However, I want to customize the order, rather than sorting by ascending or descending.
So the final output should look similar to this...
Drop off
Company One
2 Miles
Drop off
Company Two
5 Miles
Retail Store
Company Three
1.5 Miles
Contractor
Company Four
7 Miles
Contractor
Company Five
10 Miles
I'm looping through the $distance_array like this.
$curr_res = array();
$count = 0;
foreach($distance_array as $key => $value)
{
$curr_res = $results[$key];
echo stripslashes($curr_res['type'])."<br />";
echo stripslashes($curr_res['company_name'])."<br />";
echo number_format($value, 2, '.', '') . " Miles <br />";
$count++;
}
And my arrays look like this.
$distance_array
Array ( [10066] => 5.3109370772026 [10347] => 8.8816963223926 [66] => 12.837831771854 [10483] => 12.878820381449 [10625] => 15.002565483354 [64] => 15.29246611189 [10438] => 15.388386254936 [10327] => 19.261218858628 [10461] => 22.650257356203 [10243] => 26.26616586252 [10246] => 32.440312706073 [10422] => 45.859312064584 [10529] => 61.744883818327 [10397] => 67.358673239898 [10632] => 67.437024249966 [10547] => 74.253276511624 [10572] => 74.93732142815 [10240] => 97.381361623479 )
$curr_res
Array ( [id] => 10066 [type] => Retail Store [company_name] => Joe's Place [address] => Joes Address [city] => Madison [state] => WI [zip] => 53718 [country] => United States [lat] => 43.011803 [lng] => -89.513130 )
If I am following you it seems it would be easier to merge the arrays then do a multi sort on the two keys?
Here are the data shown above in a form that will allow testing. But it looks like this is not enough data to test with. Is there some more so that we could get something that looks more like the output in the question?
<?php // RAY_temp_jej07.php
error_reporting(E_ALL);
echo '<pre>';
// SEE http://www.experts-exchange.com/Web_Development/Web_Languages-Standards/PHP/Q_28348173.html
$distance_array = array
( '10066' => 5.3109370772026
, '10347' => 8.8816963223926
, '66' => 12.837831771854
, '10483' => 12.878820381449
, '10625' => 15.002565483354
, '64' => 15.29246611189
, '10438' => 15.388386254936
, '10327' => 19.261218858628
, '10461' => 22.650257356203
, '10243' => 26.26616586252
, '10246' => 32.440312706073
, '10422' => 45.859312064584
, '10529' => 61.744883818327
, '10397' => 67.358673239898
, '10632' => 67.437024249966
, '10547' => 74.253276511624
, '10572' => 74.93732142815
, '10240' => 97.381361623479
)
;
$curr_res = array
( 'id' => '10066'
, 'type' => 'Retail Store'
, 'company_name' => "Joe's Place"
, 'address' => 'Joes Address'
, 'city' => 'Madison'
, 'state' => 'WI'
, 'zip' => '53718'
, 'country' => 'United States'
, 'lat' => 43.011803
, 'lng' => -89.513130
)
;
// DO THE ARRAYS LOOK RIGHT? YES.
print_r($distance_array);
print_r($curr_res);
ASKER
Will this work?
Array
(
'id' => '10066'
, 'type' => 'Retail Store'
, 'company_name' => "Joe's Place"
, 'address' => 'Joes Address'
, 'city' => 'Madison'
, 'state' => 'WI'
, 'zip' => '53718'
, 'country' => 'United States'
, 'lat' => 43.011803
, 'lng' => -89.513130
)
Array
(
'id' => '10347'
, 'type' => 'Contractor'
, 'company_name' => 'Landscapes For You'
, 'address' => 'Address'
, 'city' => 'Carol Stream'
, 'state' => 'IL'
, 'zip' => '60188'
, 'country' => 'United States'
, 'lat' => 41.926319
, 'lng' => -88.132423
)
Array
(
'id' => '66'
, 'type' => 'Contractor'
, 'company_name' => 'GP and Sons'
, 'address' => 'Address'
, 'city' => 'Roselle'
, 'state' => 'IL'
, 'zip' => '60172'
, 'country' => 'United States'
, 'lat' => 41.969658
, 'lng' => -88.064316
)
Array
(
'id' => '10483'
, 'type' => 'Drop off'
, 'company_name' => 'VPS'
, 'address' => 'Address'
, 'city' => 'Gilberts'
, 'state' => 'IL'
, 'zip' => '60136'
, 'country' => 'United States'
, 'lat' => 42.100468
, 'lng' => -88.366783
)
Array
(
'id' => '10625'
, 'type' => 'Drop off'
, 'company_name' => 'Design Group LLC'
, 'address' => 'Address'
, 'city' => 'Lombard'
, 'state' => 'IL'
, 'zip' => '60148'
, 'country' => 'United States'
, 'lat' => 41.894997
, 'lng' => -88.015114
)
Array
(
'id' => '64'
, 'type' => 'Drop off'
, 'company_name' => 'Gardens Unlimited'
, 'address' => 'Address'
, 'city' => 'Lombard'
, 'state' => 'IL'
, 'zip' => '60148'
, 'country' => 'United States'
, 'lat' => 41.880955
, 'lng' => -88.012215
)
Array
(
'id' => '10438'
, 'type' => 'Contractor'
, 'company_name' => 'Along the Way'
, 'address' => 'Address'
, 'city' => 'Lombard'
, 'state' => 'IL'
, 'zip' => '60148'
, 'country' => 'United States'
, 'lat' => 41.849396
, 'lng' => -88.021149
)
Maybe so. Is the structure of the data an array of sub-arrays (for want of a better term)? The print_r() output would look like this:
Array
(
[0] => Array
(
[id] => 10066
[type] => Retail Store
[company_name] => Joe's Place
[address] => Joes Address
[city] => Madison
[state] => WI
[zip] => 53718
[country] => United States
[lat] => 43.011803
[lng] => -89.51313
)
[1] => Array
(
[id] => 10347
[type] => Contractor
[company_name] => Landscapes For You
[address] => Address
[city] => Carol Stream
[state] => IL
[zip] => 60188
[country] => United States
[lat] => 41.926319
[lng] => -88.132423
)
[2] => Array
(
[id] => 66
[type] => Contractor
[company_name] => GP and Sons
[address] => Address
[city] => Roselle
[state] => IL
[zip] => 60172
[country] => United States
[lat] => 41.969658
[lng] => -88.064316
)
[3] => Array
(
[id] => 10483
[type] => Drop off
[company_name] => VPS
[address] => Address
[city] => Gilberts
[state] => IL
[zip] => 60136
[country] => United States
[lat] => 42.100468
[lng] => -88.366783
)
[4] => Array
(
[id] => 10625
[type] => Drop off
[company_name] => Design Group LLC
[address] => Address
[city] => Lombard
[state] => IL
[zip] => 60148
[country] => United States
[lat] => 41.894997
[lng] => -88.015114
)
[5] => Array
(
[id] => 64
[type] => Drop off
[company_name] => Gardens Unlimited
[address] => Address
[city] => Lombard
[state] => IL
[zip] => 60148
[country] => United States
[lat] => 41.880955
[lng] => -88.012215
)
[6] => Array
(
[id] => 10438
[type] => Contractor
[company_name] => Along the Way
[address] => Address
[city] => Lombard
[state] => IL
[zip] => 60148
[country] => United States
[lat] => 41.849396
[lng] => -88.021149
)
)
Please see: http://www.laprbass.com/RAY_temp_jej07.php
Please post back if any of this doesn't make sense, thanks.
Please post back if any of this doesn't make sense, thanks.
<?php // RAY_temp_jej07.php
error_reporting(E_ALL);
echo '<pre>';
// SEE http://www.experts-exchange.com/Web_Development/Web_Languages-Standards/PHP/Q_28348173.html
$distance_array = array
( '10066' => 5.3109370772026
, '10347' => 8.8816963223926
, '66' => 12.837831771854
, '10483' => 12.878820381449
, '10625' => 15.002565483354
, '64' => 15.29246611189
, '10438' => 15.388386254936
, '10327' => 19.261218858628
, '10461' => 22.650257356203
, '10243' => 26.26616586252
, '10246' => 32.440312706073
, '10422' => 45.859312064584
, '10529' => 61.744883818327
, '10397' => 67.358673239898
, '10632' => 67.437024249966
, '10547' => 74.253276511624
, '10572' => 74.93732142815
, '10240' => 97.381361623479
)
;
$curr_res = array
(
array
( 'id' => '10066'
, 'type' => 'Retail Store'
, 'company_name' => "Joe's Place"
, 'address' => 'Joes Address'
, 'city' => 'Madison'
, 'state' => 'WI'
, 'zip' => '53718'
, 'country' => 'United States'
, 'lat' => 43.011803
, 'lng' => -89.513130
)
,
array
( 'id' => '10347'
, 'type' => 'Contractor'
, 'company_name' => 'Landscapes For You'
, 'address' => 'Address'
, 'city' => 'Carol Stream'
, 'state' => 'IL'
, 'zip' => '60188'
, 'country' => 'United States'
, 'lat' => 41.926319
, 'lng' => -88.132423
)
,
array
( 'id' => '66'
, 'type' => 'Contractor'
, 'company_name' => 'GP and Sons'
, 'address' => 'Address'
, 'city' => 'Roselle'
, 'state' => 'IL'
, 'zip' => '60172'
, 'country' => 'United States'
, 'lat' => 41.969658
, 'lng' => -88.064316
)
,
array
( 'id' => '10483'
, 'type' => 'Drop off'
, 'company_name' => 'VPS'
, 'address' => 'Address'
, 'city' => 'Gilberts'
, 'state' => 'IL'
, 'zip' => '60136'
, 'country' => 'United States'
, 'lat' => 42.100468
, 'lng' => -88.366783
)
,
array
( 'id' => '10625'
, 'type' => 'Drop off'
, 'company_name' => 'Design Group LLC'
, 'address' => 'Address'
, 'city' => 'Lombard'
, 'state' => 'IL'
, 'zip' => '60148'
, 'country' => 'United States'
, 'lat' => 41.894997
, 'lng' => -88.015114
)
,
array
( 'id' => '64'
, 'type' => 'Drop off'
, 'company_name' => 'Gardens Unlimited'
, 'address' => 'Address'
, 'city' => 'Lombard'
, 'state' => 'IL'
, 'zip' => '60148'
, 'country' => 'United States'
, 'lat' => 41.880955
, 'lng' => -88.012215
)
,
array
( 'id' => '10438'
, 'type' => 'Contractor'
, 'company_name' => 'Along the Way'
, 'address' => 'Address'
, 'city' => 'Lombard'
, 'state' => 'IL'
, 'zip' => '60148'
, 'country' => 'United States'
, 'lat' => 41.849396
, 'lng' => -88.021149
)
)
;
// ACTIVATE THIS TO SEE IF THE INITIAL ARRAYS LOOK RIGHT
// var_dump($distance_array, $curr_res);
// CONFIGURE A NON-NATURAL LANGUAGE SORT ORDER
$order_keys = array
( 'Drop off' => 10
, 'Retail Store' => 20
, 'Contractor' => 30
)
;
// INJECT THE SORT ORDER KEYS INTO THE SUB-ARRAYS
foreach ($curr_res as $key => $sub)
{
$sub['order'] = $order_keys[$sub['type']];
$curr_res[$key] = $sub;
}
// USE PHP USORT() TO ARRANGE THE ARRAY ELEMENTS IN THE SORT ORDER
function my_order($a, $b)
{
if ($a["order"] == $b["order"]) return 0;
return ($a["order"] < $b["order"]) ? -1 : 1;
}
usort($curr_res, 'my_order');
// SHOW THE NEW ORDER OF THINGS
foreach ($curr_res as $sub)
{
$distance = $distance_array[$sub['id']];
echo PHP_EOL . $sub['type'];
echo PHP_EOL . $sub['company_name'];
echo PHP_EOL . number_format($distance,1) . ' Miles';
echo PHP_EOL;
}
Best regards, ~Ray
ASKER
Wow! I'm away from my computer and can't test it but I think you nailed it. I'll have to take a closer look at how you made it work. Based on the output I may also need to change the order within each group so the closest comes up first
The ordering process is done in the callback function for usort(). As written above it's only ordering according to the forced sort order. It could be made to order within the forced sort order by adding the distance to the forced sort order (and of course making the forced sort order values into very large numbers).
The problem you may run into with this algorithm is directional. If the only value you check within an order group is the distance, you could find the algorithm routing the driver 1 mile north(A), followed by 3 miles south(B), then 5 miles north(C), then 7 miles south(D).
1+3+5+7 = 16
But a better route would be 1 mile north(A), 2 miles north(C), 5 miles south(B), 2 miles south(D).
1+2+5+2 = 10
This is advanced mathematics. It's commonly known as the Shortest Path Problem and it's one I encountered in organizing carpools. My algorithm did not take account of the fact that two drivers each two miles away from a destination might be on opposite sides of the destination. I took the easy way out and decided to ignore the problem. My carpools were intended for very long distance trips intercity, so it was not a "real" problem in practice. But I never implemented the algorithm that solved the problem.
The problem you may run into with this algorithm is directional. If the only value you check within an order group is the distance, you could find the algorithm routing the driver 1 mile north(A), followed by 3 miles south(B), then 5 miles north(C), then 7 miles south(D).
1+3+5+7 = 16
But a better route would be 1 mile north(A), 2 miles north(C), 5 miles south(B), 2 miles south(D).
1+2+5+2 = 10
This is advanced mathematics. It's commonly known as the Shortest Path Problem and it's one I encountered in organizing carpools. My algorithm did not take account of the fact that two drivers each two miles away from a destination might be on opposite sides of the destination. I took the easy way out and decided to ignore the problem. My carpools were intended for very long distance trips intercity, so it was not a "real" problem in practice. But I never implemented the algorithm that solved the problem.
ASKER
I have not been able to get this to work yet, but it's my own fault. Looking back at my original code, and your post referring to sub-arrays, I realized I had made a mistake. I'm finding the distance $key first (eg. 10066), then using that to extract the correct $result key (eg. 10066), which becomes the $curr_res keys and values. So, I think what I actually need to do is order the $results array, based on the new $order_keys array, as done below. Then order that result based on the distance. Maybe by merging the distance_array with the results array?
Below, is what I'm using for testing. I changed some of the type values just to get a better idea how it was ordering each. I also included the correct structure of what's actually the $results array.
I would like to get it so the final output looks like this:
Drop off
Gardens Unlimited
15.3 Miles
Drop off
Test 1
20.4 Miles
Retail Store
Test 3
2.4 Miles
Retail Store
Joe's Place
5.3 Miles
Retail Store
Test 2
23.4 Miles
Contractor
Landscapes For You
8.9 Miles
Contractor
GP and Sons
12.8 Miles
Contractor
VPS
12.9 Miles
Contractor
Test
13.4 Miles
Contractor
Design Group LLC
15.0 Miles
Contractor
Along the Way
15.4 Miles
Below, is what I'm using for testing. I changed some of the type values just to get a better idea how it was ordering each. I also included the correct structure of what's actually the $results array.
$distance_array = array
( '10066' => 5.3109370772026
, '10347' => 8.8816963223926
, '66' => 12.837831771854
, '10483' => 12.878820381449
, '10625' => 15.002565483354
, '64' => 15.29246611189
, '10438' => 15.388386254936
, '10000' => 13.388386254936
, '10001' => 20.388386254936
, '10002' => 23.388386254936
, '10003' => 2.3883862549365
)
;
$results = array
(
'10066' => Array (
'id' => '10066'
, 'type' => 'Retail Store'
, 'company_name' => "Joe's Place"
, 'address' => 'Joes Address'
, 'city' => 'Madison'
, 'state' => 'WI'
, 'zip' => '53718'
, 'country' => 'United States'
, 'lat' => 43.011803
, 'lng' => -89.513130
)
,
'10347' => Array (
'id' => '10347'
, 'type' => 'Contractor'
, 'company_name' => 'Landscapes For You'
, 'address' => 'Address'
, 'city' => 'Carol Stream'
, 'state' => 'IL'
, 'zip' => '60188'
, 'country' => 'United States'
, 'lat' => 41.926319
, 'lng' => -88.132423
)
,
'66' => Array (
'id' => '66'
, 'type' => 'Contractor'
, 'company_name' => 'GP and Sons'
, 'address' => 'Address'
, 'city' => 'Roselle'
, 'state' => 'IL'
, 'zip' => '60172'
, 'country' => 'United States'
, 'lat' => 41.969658
, 'lng' => -88.064316
)
,
'10483' => Array (
'id' => '10483'
, 'type' => 'Contractor'
, 'company_name' => 'VPS'
, 'address' => 'Address'
, 'city' => 'Gilberts'
, 'state' => 'IL'
, 'zip' => '60136'
, 'country' => 'United States'
, 'lat' => 42.100468
, 'lng' => -88.366783
)
,
'10625' => Array (
'id' => '10625'
, 'type' => 'Contractor'
, 'company_name' => 'Design Group LLC'
, 'address' => 'Address'
, 'city' => 'Lombard'
, 'state' => 'IL'
, 'zip' => '60148'
, 'country' => 'United States'
, 'lat' => 41.894997
, 'lng' => -88.015114
)
,
'64' => Array (
'id' => '64'
, 'type' => 'Drop off'
, 'company_name' => 'Gardens Unlimited'
, 'address' => 'Address'
, 'city' => 'Lombard'
, 'state' => 'IL'
, 'zip' => '60148'
, 'country' => 'United States'
, 'lat' => 41.880955
, 'lng' => -88.012215
)
,
'10438' => Array (
'id' => '10438'
, 'type' => 'Contractor'
, 'company_name' => 'Along the Way'
, 'address' => 'Address'
, 'city' => 'Lombard'
, 'state' => 'IL'
, 'zip' => '60148'
, 'country' => 'United States'
, 'lat' => 41.849396
, 'lng' => -88.021149
)
,
'10000' => Array (
'id' => '10000'
, 'type' => 'Contractor'
, 'company_name' => 'Test'
)
,
'10001' => Array (
'id' => '10001'
, 'type' => 'Drop off'
, 'company_name' => 'Test 1'
)
,
'10002' => Array (
'id' => '10002'
, 'type' => 'Retail Store'
, 'company_name' => 'Test 2'
)
,
'10003' => Array (
'id' => '10003'
, 'type' => 'Retail Store'
, 'company_name' => 'Test 3'
)
,
)
;
/*
echo 'results array <br /><pre>';
print_r($results);
echo ' </pre><br /> end results array <br />';
*/
// CONFIGURE A NON-NATURAL LANGUAGE SORT ORDER
$order_keys = array (
'Drop off' => 10
, 'Retail Store' => 20
, 'Contractor' => 30
);
// INJECT THE SORT ORDER KEYS INTO THE SUB-ARRAYS
foreach ($results as $key => $sub)
{
$sub['order'] = $order_keys[$sub['type']];
$results[$key] = $sub;
}
// USE PHP USORT() TO ARRANGE THE ARRAY ELEMENTS IN THE SORT ORDER
function my_order($a, $b)
{
if ($a["order"] == $b["order"]) return 0;
return ($a["order"] < $b["order"]) ? -1 : 1;
}
usort($results, 'my_order');
// SHOW THE NEW ORDER OF THINGS
foreach ($results as $sub)
{
$distance = $distance_array[$sub['id']];
echo PHP_EOL . '<pre>';
echo PHP_EOL . $sub['type'];
echo PHP_EOL . $sub['company_name'];
echo PHP_EOL . number_format($distance,1) . ' Miles';
echo PHP_EOL;
echo PHP_EOL . '</pre>';
}
I would like to get it so the final output looks like this:
Drop off
Gardens Unlimited
15.3 Miles
Drop off
Test 1
20.4 Miles
Retail Store
Test 3
2.4 Miles
Retail Store
Joe's Place
5.3 Miles
Retail Store
Test 2
23.4 Miles
Contractor
Landscapes For You
8.9 Miles
Contractor
GP and Sons
12.8 Miles
Contractor
VPS
12.9 Miles
Contractor
Test
13.4 Miles
Contractor
Design Group LLC
15.0 Miles
Contractor
Along the Way
15.4 Miles
$order_keys array? I don't follow.
Would I be on firm ground to say that you want to do all of the Drop Off first, Retail Store second and Contractor third? And within each group you want to do them in ascending distance?
ASKER
I'm sorry for making a mess of this, but I believe it's helping me to get a better grasp. The $order_keys array contains the unnatural sort order.
You're also correct in that it should be Drop Off, then Retail Store and finally Contractor. And each group should be sorted by ascending distance.
You're also correct in that it should be Drop Off, then Retail Store and finally Contractor. And each group should be sorted by ascending distance.
I believe that there are some caveats about usort() and preservation of the original order, so two consecutive sorts might not be the best thing. I don't know this for sure, it's just a feeling I have. Example: I do not know if this user-contributed code is 100% dependable.
http://php.net/manual/en/function.usort.php#105764
So the strategy will be to inject distance into each sub-array, sort by distance, then distribute into the type arrays and merge the resulting arrays. I'll see if this works as expected and post back in a little while.
http://php.net/manual/en/function.usort.php#105764
So the strategy will be to inject distance into each sub-array, sort by distance, then distribute into the type arrays and merge the resulting arrays. I'll see if this works as expected and post back in a little while.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
That's it!!! Ray, I wish I could buy you a drink, because 500 points just doesn't seem like enough.
The data should be clean, with very little opportunity for duplicates. However, I will keep in mind the fact that key could cause problems.
Thank you so much for your help!
The data should be clean, with very little opportunity for duplicates. However, I will keep in mind the fact that key could cause problems.
Thank you so much for your help!
Ha! Thanks for the points and thanks for using EE. All the best, ~Ray