3

I've got the below $test array sorted by 'date' and 'site'.

$test = array ( 
0 => array ( 
       'id' => '45', 
       'rating' => 'p1', 
       'site' => 'Heavener SW', 
       'time' => '11-03-2012 Sat 10:00:00', 
       ), 
1 => array ( 
       'id' => '45', 
       'rating' => 'h3', 
       'site' => 'Heavener SW', 
       'time' => '11-03-2012 Sat 10:00:00', 
       ),
2 => array ( 
       'id' => '45', 
       'rating' => 'h4', 
       'site' => 'Heavener SW', 
       'time' => '11-03-2012 Sat 16:00:00', 
       ),
3 => array ( 
       'id' => '110', 
       'rating' => 'p3', 
       'site' => 'Red Oak', 
       'time' => '11-03-2012 Sat 16:00:00', 
       ), 
4 => array ( 
       'id' => '110', 
       'rating' => 'h3', 
       'site' => 'Red Oak', 
       'time' => '11-03-2012 Sat 16:00:00', 
       ), 
5 => array ( 
       'id' => '32', 
       'rating' => 'p2', 
       'site' => 'Panopoint', 
       'time' => '11-04-2012 Sun 10:00:00', 
       ) 
 );

I've gone nuts trying to combine 'ratings' for each 'site'-'time' combination.

$result = array (
0 => array ( 
       'id' => '45', 
       'rating' => 'p1, h3', 
       'site' => 'Heavener SW',
       'time' => '11-03-2012 Sat 10:00:00', 
       ),
2 => array ( 
       'id' => '45', 
       'rating' => 'h4', 
       'site' => 'Heavener SW', 
       'time' => '11-03-2012 Sat 16:00:00', 
       ),
3 => array ( 
       'id' => '110', 
       'rating' => 'p3, h3', 
       'site' => 'Red Oak', 
       'time' => '11-03-2012 Sat 16:00:00', 
       ),
5 => array ( 
       'id' => '32', 
       'rating' => 'p2', 
       'site' => 'Panopoint', 
       'time' => '11-04-2012 Sun 10:00:00', 
       ) 
 );

There's no limits on the number of 'ratings' a site can have or how many 'sites' or 'time' there are (within reason). Preserving the index in the $result is optional (ie. not necessary).

I found this similar post(and others) but I don't understand how to implement. Getting all the related ones based on value

I've tried so many differnt ways my head is spinning, any help is greatly appreciated!

3
  • To ge grouped together, do the times have to be exactly the same, or do you want to group them by the same day/hour/whatever? Commented Nov 3, 2012 at 23:30
  • wow! baba et.al. it's late I'll review tomorrow. Can't express my gratitude sufficiently. slashingweapon times remain only ratings are consolidated. Commented Nov 4, 2012 at 3:24
  • Appreciate the help from all. Clearly the slickest answer 'array_reduce' by baba is what I'm going with. Thanks All. Commented Nov 4, 2012 at 13:20

3 Answers 3

2

You can simply use array_reduce

$test = array_reduce($test, function ($a, $b) {
    isset($a[$b['time'] . "|" . $b['id']]) ? $a[$b['time'] . "|" . $b['id']]['rating'] .= "," . $b['rating'] : $a[$b['time'] . "|" . $b['id']] = $b;
    return $a;
});

$test = array_values($test);
var_dump($test);

Output

array
  0 => 
    array
      'id' => string '45' (length=2)
      'rating' => string 'p1,h3' (length=5)
      'site' => string 'Heavener SW' (length=11)
      'time' => string '11-03-2012 Sat 10:00:00' (length=23)
  1 => 
    array
      'id' => string '45' (length=2)
      'rating' => string 'h4' (length=2)
      'site' => string 'Heavener SW' (length=11)
      'time' => string '11-03-2012 Sat 16:00:00' (length=23)
  2 => 
    array
      'id' => string '110' (length=3)
      'rating' => string 'p3,h3' (length=5)
      'site' => string 'Red Oak' (length=7)
      'time' => string '11-03-2012 Sat 16:00:00' (length=23)
  3 => 
    array
      'id' => string '32' (length=2)
      'rating' => string 'p2' (length=2)
      'site' => string 'Panopoint' (length=9)
      'time' => string '11-04-2012 Sun 10:00:00' (length=23)

See Live Demo

Sign up to request clarification or add additional context in comments.

Comments

1

Since preserving the keys is optional, an easy option is to build a new array keyed by the unique pair site|time while looping over the original.

For each of those, we'll also create an array of rating values, and finally, implode() that array into a string back to the 'ratings' key.

$rekeyed = array();
foreach ($test as $item) {
  // Build temporary key by concatenating site, time
  $key = $item['site'] . '|' . $item['time'];
  // If it already exists, add to the ratings
  if (isset($rekeyed[$key])) {
    $rekeyed[$key]['ratings'][] = $item['rating'];
  }
  else {
    // Otherwise, set the key and the ratings array
    $rekeyed[$key] = $item;
    // And set the first rating, initialized as an array
    $rekeyed[$key]['ratings'] = array();
    $rekeyed[$key]['ratings'][] = $item['rating'];
  }
}

// Finally, loop over and implode all the ratings back into a comma-separated string
foreach ($rekeyed as &$item) {
  $item['rating'] = implode(',', $item['ratings']);
  // Don't need the 'ratings' array anymore, unset it
  unset($item['ratings']);
}

var_dump($rekeyed);

Outputs:

array(4) {
  ["Heavener SW|11-03-2012 Sat 10:00:00"]=>
  array(5) {
    ["id"]=>
    string(2) "45"
    ["rating"]=>
    string(5) "p1,h3"
    ["site"]=>
    string(11) "Heavener SW"
    ["time"]=>
    string(23) "11-03-2012 Sat 10:00:00"
  }
  ["Heavener SW|11-03-2012 Sat 16:00:00"]=>
  array(5) {
    ["id"]=>
    string(2) "45"
    ["rating"]=>
    string(2) "h4"
    ["site"]=>
    string(11) "Heavener SW"
    ["time"]=>
    string(23) "11-03-2012 Sat 16:00:00"
  }
  ["Red Oak|11-03-2012 Sat 16:00:00"]=>
  array(5) {
    ["id"]=>
    string(3) "110"
    ["rating"]=>
    string(5) "p3,h3"
    ["site"]=>
    string(7) "Red Oak"
    ["time"]=>
    string(23) "11-03-2012 Sat 16:00:00"
  }
  ["Panopoint|11-04-2012 Sun 10:00:00"]=>
  &array(5) {
    ["id"]=>
    string(2) "32"
    ["rating"]=>
    string(2) "p2"
    ["site"]=>
    string(9) "Panopoint"
    ["time"]=>
    string(23) "11-04-2012 Sun 10:00:00"
  }
}

Comments

0

I think PHP foreach loops go in order, so this should work. I haven't tested it, so let me know how it goes.

$previous_id = '';
// for each row, check if it was the same as the previous row (since you have sorted it properly)
foreach($result as $k => $row){
    // if it matches the previous, add the rating and remove now duplicate row
    if ($row['time'] == $result[$previous_id]['time']
     && $row['site'] == $result[$previous_id]['site']){
        $result[$previous_id]['rating'] .= ', '.$row['rating'];
        unset($result[$k]);
    } // otherwise, set new previous_id to check
    else {
        $previous_id = $k;
    }
}

This has the added benefit of keeping the first row-id that you come across, but may not be particularly optimized.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.