php находит max в 2-мерном массиве, но возвращает другой элемент ('id') массива - PullRequest
0 голосов
/ 05 августа 2011

вот мой образец массива $data[][];

Array( [0] => Array ( [id] => 1349
                      [rating1] => 1.9378838029981E-7
                      [rating2] => 1.1801796607774     )
       [1] => Array ( [id] => 1350
                      [rating1] => 5.5499981876923E-7
                      [rating2] => 1.5121329727308     )
       [2] => Array ( [id] => 1377
                      [rating1] => 0.00023952225410117
                      [rating2] => 2.1947077830236     )
       [3] => Array ( [id] => 1378
                      [rating1] => 0.00022982302863634
                      [rating2] => 2.2135588326622     )
       [4] => Array ( [id] => 1379
                      [rating1] => 0.00026272979843585
                      [rating2] => 2.2388295595073     )
       [5] => Array ( [id] => 1380
                      [rating1] => 0.0002788640872546
                      [rating2] => 2.1815325502993     )
)

Я хочу найти max($data[][rating?]), но вернуть $data[id][max_rating?] то есть id, связанный со значением max.
Поискmax было легко для одного конкретного, скажем, rating1, я использовал array_reduce следующим образом (это вдохновлено this SO ):

$max = array_reduce($data, function($a, $b) {
    return $a > $b['rating1'] ? $a : $b['rating1']; 
});

Теперь у меня два вопроса:
1. Как я могу расширить выше array_reduce, чтобы включить rating2?У меня есть и другой рейтингX.
2. Мне не нужно значение max, а $data[][id], связанное с max.

Меня не очень беспокоит вопрос Q1, но второй вопрос важен, так как я не хочу снова искать в массиве, чтобы получить связь $data[][id].
Одна из идей заключается в использованииarray_map вместо array_reduce, но я не смог придумать версию, которая будет передавать как [id], так и [rating?].Кроме того, возникают сложности, когда я пытаюсь max() кратно rating? за один выстрел, так как каждый рейтинг будет иметь разные max, что, в свою очередь, ассоциируется с разными [id].
РЕДАКТИРОВАТЬ.Я хочу, чтобы все соответствующие id были связаны с соответствующими max каждого rating?

Ответы [ 2 ]

1 голос
/ 05 августа 2011
$max = array_reduce($data, function($a, $b) {    
  if (is_null($a)) return $b;
  return max($a['rating1'],$a['rating2'])>max($b['rating1'],$b['rating2']) ? $a : $b;
});

Результат: нет записей $max= NULL в противном случае $max['id'] - это идентификатор с максимальной оценкой

В качестве альтернативы этот универсальный код

$max = array_reduce($data, function($a, $b) {
   if (is_null($a)) return $b;
   return maxRating($a)>maxRating($b) ? $a : $b;
 });

function maxRating($row){
   return (max(array_intersect_key($row,array_flip(array_filter(array_keys($row),function ($item) { return strstr($item,'rating')!==FALSE;})))));
}

найдете для всех рейтингов форму рейтинга?

РЕДАКТИРОВАТЬ - Код пытался ответить Q1 здесь ответ только для Q2

$max = array_reduce($data, function($a, $b) {    
  if (is_null($a)) return $b;
  return $a['rating1']>$b['rating1'] ? $a : $b;
});

EDIT2 - это универсальное решение для любого количества рейтинга? Столбцы

$ratingKeys=array_filter(array_keys($data[0]),function ($item) { return strstr($item,'rating')!==FALSE;});

$max = array_reduce($data,function($a,$b) use (&$ratingKeys) {
  if (is_null($a)) {
    $a=array();
    foreach($ratingKeys as $key) {
      $a[$key]=$b[$key];
      $a[$key.'_id'] = $b['id'];
     }
     return $a;
  }
  foreach($ratingKeys as $key) {
    if ($a[$key]<$b[$key]) {
      $a[$key]=$b[$key];
      $a[$key.'_id']=$b['id'];
    }
  }
  return $a;
});

Этот код приводит к

array(4) {
  ["rating1"]=> float(0.0002788640872546)
  ["rating1_id"]=> int(1380)
  ["rating2"]=> float(2.2388295595073)
  ["rating2_id"]=> int(1379)
}

РЕДАКТИРОВАТЬ 3 - Если вы измените формат входного массива для использования идентификатора в качестве ключа массива, вы можете значительно упростить

$max=array_reduce(array_keys($data),function ($a,$b) use (&$data) {
  if (is_null($a)) $a=array();
    foreach(array_keys($data[$b]) as $item) {
      if (!isset($a[$item]) {
        $a[$item] = $b;
      } else {
        if ($data[$a[$item]][$item]) < $data[$b][$item]) $a[$item]=$b;
      }
    return $a;
  }
});

Этот код приводит к

array(2) {
  ["rating1"]=> int(1380)
  ["rating2"]=> int(1379)
}
1 голос
/ 05 августа 2011

при условии, что ваш массив не отсортирован, вы должны пройти через него хотя бы один раз (вручную или с помощью встроенных функций).я бы использовал следующий код:

$array = array(
  array( 'id' => 1349, 'sudhi_rating1' => 1.9378838029981E-7, 'sudhi_rating2' => 1.1801796607774 ),
  array( /* … */ ),
  /* … */
);

$idx_max = 0;
foreach($array as $idx => $item) {
  if($item['sudhi_rating1'] > $array[$idx_max]['sudhi_rating1'])
    $idx_max = $idx;
}

echo "Rating 1 has max value at id ", htmlspecialchars($array[$idx_max]['id']);

вы можете расширить код для проверки нескольких рейтингов одновременно (сделать $idx_max сам массив и добавить больше ifs):

$idx_max = array (
  'sudhi_rating1' => 0,
  'sudhi_rating2' => 0,
  /* … */ );
foreach($array as $idx => $item) {
  foreach($idx_max as $rating => &$max) {
    if($item[$rating] > $array[$max][$rating])
      $max = $idx;
  }
}

foreach($idx_max as $rating => $max)
  echo 'Max value for ', htmlspecialchars($rating), ' has id ', htmlspeciachars($array[$max]['id']);
...