PHP sorting a set of multidimensional arrays - php

I have an array which contains another array with a distance and ID in it. I need to sort the distance part of the array, so the ID remains correlated with it's respective distance.
Eg.
array
(
[0] => array(
[0] => 170
[1] => 123abc
)
[1] => array(
[0] => 150
[1] => 456def
)
)
Now, I want to sort the distances ascending so my sorted output would look like:
array
(
[0] => array(
[0] => 150
[1] => 456def
)
[1] => array(
[0] => 170
[1] => 123abc
)
)
As 150 is smaller than 170, it has 'moved' up.
I've looked at the PHP functions for this; array_multisort() etc. however these only seem to sort the values within the arrays rather than a set of arrays.
Any help appreciated.
EDIT:
There isn't a fixed number of items within the first array - it ranges from 1 to infinity.

use usort
usort($yourArray, function($a, $b) {
return $a[0] - $b[0]; // index 0 is your 150 or 170
});

Related

Sorting CSV Data By A Column With PHP

I've looked on Stack Overflow with no solution that seems to work. Know that I'm a newbie!
Suppose I have a file (data.csv) with the following contents:
year,total
1990,57.58
2011,73.28
1880,54.67
1996,53.41
1950,53.22
1979,52.76
1876,52.62
1883,52.35
1882,52.12
2018,52.23
...then import the data with PHP:
$csv = array_map('str_getcsv', file('data.csv'));
How would I sort both the year and total by the total column in ascending order (such that 1882/52.12 are under $csv[0] in the array and 2011/73.28 are under $csv[10]?
The following and a print($csv); does not seem to be getting the items in the right order:
function compare($a, $b) {
return ($b[0][1] - $a[0][1]);
}
usort($csv, "compare");
Do I need to use typecasting? Thank you!
This will do the trick:
You have to modify the function like this:
function compare($a, $b)
{
// here, comparing "total" column of each row:
return $a[1] >= $b[1] ? 1 : -1;
}
And the new ordering will be:
Array
(
[0] => Array
(
[0] => 1882
[1] => 52.12
)
[1] => Array
(
[0] => 2018
[1] => 52.23
)
[2] => Array
(
[0] => 1883
[1] => 52.35
)
[3] => Array
(
[0] => 1876
[1] => 52.62
)
[4] => Array
(
[0] => 1979
[1] => 52.76
)
[5] => Array
(
[0] => 1950
[1] => 53.22
)
[6] => Array
(
[0] => 1996
[1] => 53.41
)
[7] => Array
(
[0] => 1880
[1] => 54.67
)
[8] => Array
(
[0] => 1990
[1] => 57.58
)
[9] => Array
(
[0] => 2011
[1] => 73.28
)
)
Three problems with your comparison function.
The items that will be compared in your comparison function are going to be arrays corresponding to rows from your CSV file. For example, $a and $b will be things like [1990,57.58] and [1950,53.22].
When you refer to those items in your comparison function, you're looking at index [0][1], but that doesn't exist; the arrays don't have that second dimension. $a[0][1] and $b[0][1] will both be null, so no sorting happens. (You might think you'd get some kind of warning or notice for trying to refer to an int or float with an array index, but you won't, just one of the weird things about PHP.)
You want to sort in ascending order, but putting $b first will sort in descending order.
The comparison function should return an int greater than, less than, or equal to zero depending on the result of the comparison, but yours will return a float. There are various way to make it return an int. The other answer shows how to do it with a ternary expression. If you're using PHP 7, you can use the combined comparison operator, like this:
function compare($a, $b) {
return $a[1] <=> $b[1];
}
Also, you don't need to define a named comparison function, you can use an anonymous function for the second argument if you like.
usort($csv, function($a, $b) {
return $a[1] <=> $b[1];
});

Sort an array (looking a specific value) based on another array

I have this array of options, and some value of an internal array is the "ID"
[options] => Array (
[0] => Array (
[id] => 1088
[label] => John
)
[1] => Array (
[id] => 1089
[label] => Peter
)
[2] => Array (
[id] => 1050
[label] => Mary
)
....
On the other hand, I have this array:
$array_sort = array(1089, 1050, 1088, ...);
I would like the options array of the first array is sorted (looking the "id") based on the $array_sort.
I know how to do it in a very dirty way (with a lot of loops and temporary arrays), but I guess there's some smart solution of array_* functions to do this.
Thank you !
You could use array_filter to limit the options to only those in the sorted array, then usort to sort them based on their position in the $array_sort array using array_search:
$sorted = array_filter($options, function($arr) use($array_sort) {
return in_array($arr['id'], $array_sort);
});
usort($sorted, function($a, $b) use($array_sort) {
return array_search($a['id'], $array_sort) - array_search($b['id'], $array_sort);
});
// $sorted should now be the sorted array

Intersect (inner join) two arrays with different key names

I have following two multidimensional arrays:
First array:
$array_1_data = Array (
[0] => Array ( [id] => 1 [name] => IT [slug] => it )
[1] => Array ( [id] => 2 [name] => Accounting [slug] => accounting )
)
Second array:
$array_2_data = Array (
[0] => Array ( [cid] => 3 [jid] => 24061 )
[1] => Array ( [cid] => 1 [jid] => 24062 )
)
Expected result:
$some_array = Array (
[0] => Array ( [id] => 1 [name] => IT [slug] => it )
)
I won't mind having [cid] in the result.
I want to intersect these two arrays by [id] of the first array and [cid] of the second array, like inner join in MySQL. I have basic foreach and if else logic for this purpose but speed is a priority now so I'm looking for non-looped solution. For better understanding here is the basic looped solution:
foreach ($array_1_data as $array_1_row ) {
foreach ($array_2_data as $array_2_row ) {
if ($array_2_row['cid'] == $array_1_row['id']) {
//intersection iteration
}
}
}
I tried array_uintersection as follows:
array_uintersect($array_1_data, $array_2_data, function($a1, $a2){
$diff1 = strcasecmp($a1['id'], $a2['cid']);
if ($diff1 != 0) return $diff1;
return 0;
});
But it gives me undefined index 'id'. I checked this question: Comparing two arrays with different key names. First answer for this question gives a looped solution which I want to avoid. Second answer suggests changing SQL structure but I have no control over that. So,
Is there really a non-looped fast solution to this kind of situation?
The solution using array_uintersect_uassoc function:
$result = array_uintersect_uassoc($array_1_data, $array_2_data, function($a, $b){
return strcasecmp($a['id'], $b['cid']);
}, function($a, $b){
return (int) [$a, $b] == ['id', 'cid'];
});
print_r($result);
The output:
Array
(
[0] => Array
(
[id] => 1
[name] => IT
[slug] => it
)
)
According yo your condition: to intersect these two arrays by [id] of the first array and [cid] of the second array, we should consider a key comparison function for those keys only ['id', 'cid'].
Having the needed keys on each comparison step it only remain to compare their values(with value compare function)
http://php.net/manual/en/function.array-uintersect-uassoc.php
DEMO link

PHP array sorting by scored results from database

I have an array that I'm simply trying to order by a score key that contains the value that I'm trying to sort by. The desired results would change the order of the array below to display the index in the following order: [0], [2], [1].
I'm looping through the results which are pulled from a database. I'm creating a key named score and then pushing the $row2 array in to a separate array because if I use mysql_data_seek it gets rid of the score key.
Also it's creating an unwanted key score at the bottom.
How can I best clean this up and make sure the results are ordered high to low as desired?
$my_array = array();
while ($row2 = mysql_fetch_assoc($result2))
{
//score determined here
//$row2['score'] = ...more math, variable is numeric, not a string
array_push($array_page,$row2);
}
Current undesired results...
Array
(
[0] => Array
(
[score] => 7
)
[1] => Array
(
[score] => 2
)
[2] => Array
(
[score] => 4
)
[score] =>
)
Desired results...
Array
(
[0] => Array
(
[score] => 7
)
[2] => Array
(
[score] => 4
)
[1] => Array
(
[score] => 2
)
)
function scoreSort($a, $b){
if($a['score'] == $b['score']) return 0;
return $a['score'] > $b['score'] ? -1 : 1;
}
usort(&$myArray, 'scoreSort');
on php>5.3 you can use inline-functoins:
usort(&$myArray, function($a,$b){ /* ... */ });

Sort a multi-dimensional array by the size of its sub-arrays

I have this multidimensional array:
Array
(
[0] => Array
(
[0] => 2012-02-26 07:15:00
)
[1] => Array
(
[0] => 2012-02-26 17:45:00
[1] => 2012-02-26 18:55:00
)
[2] => Array
(
[0] => 2012-02-26 18:55:00
[1] => 2012-02-26 17:45:00
)
[3] => Array
(
[0] => 2012-02-26 18:57:00
[1] => 2012-02-26 17:45:00
[2] => 2012-02-26 18:55:00
)
When I count subarrays I get this 1,2,2,3. How could I receive it in 3,2,2,1? I need to get for example last 3 subarrays with the highest subarray count (DESC, it means 3,2,2). How can I achieve this?
You can achieve it by utilizing usort function.
function cmp($a, $b){
return (count($b) - count($a));
}
usort($array, 'cmp');
$highest_3_sub_arrays = array_slice($array, 0, 3);
This might be what you seek:
natsort($sub_count);
$rev = array_reverse($sub_count);
$result = array_pad($rev, 3);
You might want to omit the actual sorting if the values you have are already in order.
$sizes=array();
foreach ($myarray as $k=>$v)
if (!is_array($v)) $sizes["$k"]=0;
else $sizes["$k"]=sizeof($v);
sort($sizes);
echo array_pop($sizes); //outputs 3
echo array_pop($sizes); //outputs 2
echo array_pop($sizes); //outputs 2
It seems to me that all of the other answers are working too hard. usort(), count(), and foreach() aren't necessary and when I tried natsort() it gave me: <b>Notice</b>: Array to string conversion in <b>[...][...]</b>.
rsort() will put the longest subarrays first.
Code:
$array=array(
["2012-02-26 18:55:00","2012-02-26 17:45:00"],
["2012-02-26 07:15:00"],
["2012-02-26 18:57:00","2012-02-26 17:45:00","2012-02-26 18:55:00"],
["2012-02-26 17:45:00","2012-02-26 18:55:00"]
);
$size=3; // modify this line to declare how many subarrays to capture
rsort($array); // sort the subarrays in DESC order
var_export(array_slice($array,0,$size)); // print the first n subarrays
Output:
array (
0 =>
array (
0 => '2012-02-26 18:57:00',
1 => '2012-02-26 17:45:00',
2 => '2012-02-26 18:55:00',
),
1 =>
array (
0 => '2012-02-26 18:55:00',
1 => '2012-02-26 17:45:00',
),
2 =>
array (
0 => '2012-02-26 17:45:00',
1 => '2012-02-26 18:55:00',
),
)
If you want to implement some additional sorting to break the length-ties (like between your two 2-element subarrays), then you will need to specify that in your question.

Categories