Сортировка массива по нескольким повторяющимся значениям в PHP - PullRequest
2 голосов
/ 26 октября 2011

У меня есть массив, содержащий строки этого формата:

[0] => "title|url|score|user|date"
[1] => "title|url|score|user|date"
[2] => "title|url|score|user|date"
[3] => "title|url|score|user|date"
...

Поле score представляет собой целое число, которое не всегда уникально (например, более одной записи может иметь оценку 0). Я хочу отсортировать строки в этом массиве на основе их значения score. Первоначально я пытался перебрать массив и создать новый с ключами, соответствующими подсчету голосов. Вскоре я понял, что в массиве нельзя использовать дубликаты ключей.

Есть ли хороший чистый способ сделать это?

Ответы [ 6 ]

2 голосов
/ 26 октября 2011
$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 );
2 голосов
/ 26 октября 2011

Загляните в PHP usort function

function score_sort($rec1, $rec2)
{
  return $rec1['score'] - $rec2['score'];
}

usort($score_array);

Заменить ['score'] на то, что вы извлекаете оценки из строк

1 голос
/ 26 октября 2011

Было бы очень легко использовать функцию asort :

$pattern = '#^([^|]+)\|([^|]+)\|([^|]+)\|([^|]+)\|([^|]+)$#';
$sorted = array();
foreach($data as $s) $sorted[] = preg_replace($pattern, '$3|$1|$2|$4|$5', $s);
asort($sorted);

эти 4 строки кода, когда дано $ 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
)

сгенерирует $ 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
)

, и только с 2 дополнительными строками вы можете получитьэлементы в каждом элементе массива возвращаются в исходном порядке / формате:

$data = array();
foreach($sorted as $s) $data[] = preg_replace($pattern, '$2|$3|$1|$4|$5', $s);

, установив $ data в:

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
)
1 голос
/ 26 октября 2011

Лично у меня возникнет соблазн перебрать массив, разделить его на | и поместить в новый многомерный массив, например, что-то вроде этого:

[0] => array([title]=>'title',[url]=>'url',[score]=>'score',[user]=>'user',[date]=>'date')
[1] => array([title]=>'title',[url]=>'url',[score]=>'score',[user]=>'user',[date]=>'date')

Затемстановится легко сортировать, просто используйте функцию, подобную этой:

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;
 }

т.е. сделайте это:

$sortedarray = sortmulti($array,'score','asc');
1 голос
/ 26 октября 2011

Сначала вам нужно превратить строки в массивы с помощью explode, чтобы вы могли сделать сравнения:

// 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);

Это сделает $converted похожим на:

array (
  0 => array (
    'title' => 'Foo',
    'url' => 'http://foo',
    'score' => '0',
    'user' => 'user1',
    'date' => 'today',
  ),
)

Затем вы можете отсортировать массив, используя код из моего ответа здесь , легко указав любой критерий сортировки:

usort($converted, make_converter('score', 'date', 'title'));
0 голосов
/ 26 октября 2011

Создать новый массив массивов:

[0] => array("score", old_array[0])

Тогда сортируй.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...