开发者

php find max in 2 dimension array but return another element('id') of the array

开发者 https://www.devze.com 2023-03-25 08:30 出处:网络
here is my array sample $data[][]; Array( [0] => Array ( [id] => 1349 [rating1] => 1.9378838029981E-7

here is my array sample $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     )
)

I want to find max($data[][rating?]) but return $data[id][max_rating?] i.e. id associated with the max value.

Finding the max was easy for one particular, say rating1, I used array_reduce as follows (this is inspired from this SO ):

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

Now I have two questions :

1. How can I extend above array_reduce to include rating2 ? I have other ratingX as well.

2. I do not want the max value, rather the $data[][id] associated with the max.

I am not so much concerned about Q1, but the second one is important as I don't want to search through the array again to get associated $data[][id].

One line of thought is to use array_map instead of array_reduce, but I couldn't come up with a version which will pass on both [id] and [rating?]. Also, there are complications when I try to max() multiple rating? at one shot, as each rating will have different max, which in turn associates with different [id].

EDIT : Just to be clear, I want all the respective ids associated wi开发者_如何学JAVAth respective max of each rating?


assuming your array is unsorted you have to loop through it at least once (either manually or using builtin functions). i'd use the following code:

$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']);

you can extend the code to check multiple ratings at once (make $idx_max an array itself and add more 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']);


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

Result: no Entries $max= NULL otherwise $max['id'] is the id with the max rating

Alternatively this generic code

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

Will find for all ratings of the form rating?

EDIT -- The code was trying to answer Q1 here is the answer for just Q2

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

EDIT2 -- This is a generic solution for any number of rating? columns

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

This code results in

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

EDIT 3 -- If you change the format of the input array to use id as the array key, you can massively simplify

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

This code results in

array(2) {
  ["rating1"]=> int(1380)
  ["rating2"]=> int(1379)
}
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号