Fredrik
Fredrik

Reputation: 1821

Sort an array by multiple keys in a certain order

I want to sort the following array by multiple keys in the following order: First by "type", then "product", and lastly by "name". This is pretty easily done with usort, although my clients wants "product" sorted in a specific order: Stapler, Binder, Book.

$arr = array(
    array(
        'type' => 'School',
        'product' => 'Book',
        'name' => 'My book',
        'data' => '...'
    ),
    array(
        'type' => 'Job',
        'product' => 'Stapler',
        'name' => 'My stapler',
        'data' => '...'
    ),
    array(
        'type' => 'Personal',
        'product' => 'Binder',
        'name' => 'My binder',
        'data' => '...'
    ),
    array(
        'type' => 'School',
        'product' => 'Book',
        'name' => 'My book',
        'data' => '...'
    )
);

Does anyone know a clever way to accomplish this?

Upvotes: 0

Views: 99

Answers (2)

Yoshi
Yoshi

Reputation: 54649

usort($arr, function ($a, $b) {
  // by type
  $r = strcmp($a['type'], $b['type']);
  if ($r !== 0) {
    return $r;
  }

  // by product
  // note: one might want to check if `$a/$b['product']` really is in `$order`
  $order = array('Stapler', 'Binder', 'Book');
  $r = array_search($a['product'], $order) - array_search($b['product'], $order);
  if ($r !== 0) {
    return $r;
  }

  // or similar, with a little help by @fab ;)
  /*
  $order = array('Stapler' => 0, 'Binder' => 1, 'Book' => 2);
  $r = $order[$a['product']] - $order[$b['product']];
  if ($r !== 0) {
    return $r;
  }
  */

  // name
  return strcmp($a['name'], $b['name']);
});

Upvotes: 1

Fabian Schmengler
Fabian Schmengler

Reputation: 24551

usort does not limit you in doing so. I assume your question is how to compare the product value in your sort callback function. This can be done with a map, like:

$mapProductOrder = array_flip(array('Stapler', 'Binder', 'Book'));
// same as: array('Stapler' => 0, 'Binder' => 1, 'Book' => 2)

To compare $item1 and $item2 use:

$mapProductOrder[$item1['product']] < $mapProductOrder[$item2['product']]

Upvotes: 1

Related Questions