Reputation:
I have an array containing strings of this format:
[0] => "title|url|score|user|date"
[1] => "title|url|score|user|date"
[2] => "title|url|score|user|date"
[3] => "title|url|score|user|date"
...
The score
field is an int that is not always unique (for example, more than one entry can have a score of 0). I'm looking to sort the strings in this array based on their score
value. Originally, I tried iterating through the array and making a new one with keys corresponding to the vote score. I soon realized that you can't have duplicate keys in an array.
Is there a good clean way of doing this?
Upvotes: 2
Views: 1393
Reputation: 11721
It would be very easy using the asort function:
$pattern = '#^([^|]+)\|([^|]+)\|([^|]+)\|([^|]+)\|([^|]+)$#';
$sorted = array();
foreach($data as $s) $sorted[] = preg_replace($pattern, '$3|$1|$2|$4|$5', $s);
asort($sorted);
these 4 lines of code, when given $data:
Array
(
[0] => title_0|url_0|6|user_0|date_0
[1] => title_1|url_1|6|user_1|date_1
[2] => title_2|url_2|2|user_2|date_2
[3] => title_3|url_3|3|user_3|date_3
[4] => title_4|url_4|2|user_4|date_4
[5] => title_5|url_5|7|user_5|date_5
[6] => title_6|url_6|3|user_6|date_6
[7] => title_7|url_7|8|user_7|date_7
[8] => title_8|url_8|3|user_8|date_8
[9] => title_9|url_9|9|user_9|date_9
)
will generate $sorted:
Array
(
[2] => 2|title_2|url_2|user_2|date_2
[4] => 2|title_4|url_4|user_4|date_4
[3] => 3|title_3|url_3|user_3|date_3
[6] => 3|title_6|url_6|user_6|date_6
[8] => 3|title_8|url_8|user_8|date_8
[0] => 6|title_0|url_0|user_0|date_0
[1] => 6|title_1|url_1|user_1|date_1
[5] => 7|title_5|url_5|user_5|date_5
[7] => 8|title_7|url_7|user_7|date_7
[9] => 9|title_9|url_9|user_9|date_9
)
and with just 2 more lines you can have the items in each element of the array back in the original order/format:
$data = array();
foreach($sorted as $s) $data[] = preg_replace($pattern, '$2|$3|$1|$4|$5', $s);
setting $data to:
Array
(
[0] => title_2|url_2|2|user_2|date_2
[1] => title_4|url_4|2|user_4|date_4
[2] => title_3|url_3|3|user_3|date_3
[3] => title_6|url_6|3|user_6|date_6
[4] => title_8|url_8|3|user_8|date_8
[5] => title_0|url_0|6|user_0|date_0
[6] => title_1|url_1|6|user_1|date_1
[7] => title_5|url_5|7|user_5|date_5
[8] => title_7|url_7|8|user_7|date_7
[9] => title_9|url_9|9|user_9|date_9
)
Upvotes: 1
Reputation: 6346
Personally I'd be tempted to iterate through the array, split it by the |'s and put it into a new multi-dimensional array, for example something like this:
[0] => array([title]=>'title',[url]=>'url',[score]=>'score',[user]=>'user',[date]=>'date')
[1] => array([title]=>'title',[url]=>'url',[score]=>'score',[user]=>'user',[date]=>'date')
Then it becomes easy to sort, just use a function like this:
function sortmulti ($array, $index, $order, $natsort=FALSE, $case_sensitive=FALSE) {
if(is_array($array) && count($array)>0) {
foreach(array_keys($array) as $key) {
$temp[$key]=$array[$key][$index];
}
if(!$natsort) {
if ($order=='asc') {
asort($temp);
} else {
arsort($temp);
}
}
else
{
if ($case_sensitive===true) {
natsort($temp);
} else {
natcasesort($temp);
}
if($order!='asc') {
$temp=array_reverse($temp,TRUE);
}
}
foreach(array_keys($temp) as $key) {
if (is_numeric($key)) {
$sorted[]=$array[$key];
} else {
$sorted[$key]=$array[$key];
}
}
return $sorted;
}
return $sorted;
}
i.e. do this:
$sortedarray = sortmulti($array,'score','asc');
Upvotes: 1
Reputation: 437834
First you need to turn the strings into arrays with explode
so you can do the comparisons:
// If using PHP >= 5.3, this can also be made into an anonymous function
function converter($string) {
$result = array_combine(
array('title', 'url', 'score', 'user', 'date'),
explode('|', $string)
);
// When these are later compared, it should be as numbers
$result['score'] = (int)$result['score'];
return $result;
}
$input = array(
'Foo|http://foo|0|user1|today',
// etc.
);
$converted = array_map('converter', $input);
This will make $converted
look like:
array (
0 => array (
'title' => 'Foo',
'url' => 'http://foo',
'score' => '0',
'user' => 'user1',
'date' => 'today',
),
)
Then you can sort the array using the code from my answer here by easily specifying any sort criteria you want:
usort($converted, make_converter('score', 'date', 'title'));
Upvotes: 1
Reputation: 22783
$array = array(
0 => "title|url|12|user|date",
1 => "title|url|0|user|date",
2 => "title|url|13|user|date",
3 => "title|url|0|user|date"
);
function sortOnScore( $a, $b )
{
// discard first two values
list( ,,$scoreA ) = explode( '|', $a );
list( ,,$scoreB ) = explode( '|', $b );
return $scoreA == $scoreB ? 0 : ( $scoreA > $scoreB ? 1 : -1 );
}
usort( $array, 'sortOnScore' );
var_dump( $array );
Upvotes: 2
Reputation: 14477
Create a new array of arrays:
[0] => array("score", old_array[0])
Then sort.
Upvotes: 0
Reputation: 2628
Look into PHP's usort function
function score_sort($rec1, $rec2)
{
return $rec1['score'] - $rec2['score'];
}
usort($score_array);
Replace ['score']
with however you are extracting the scores from the strings
Upvotes: 2