Simone Nigro
Simone Nigro

Reputation: 4887

How to sort an array of associative arrays by value of a key in PHP

Tough to explain so here's an example:

$strings = array(
   array("languageCode" => "ES",  "string" => "hola"),
   array("languageCode" => "EN",  "string" => "hello"),
   array("languageCode" => "IT",  "string" => "ciao"),
   array("languageCode" => "CHS", "string" => "您好"),
);

I would like to sort strings by languageCode value, by defining the order:

function magicStringOrder(array $strings, array $languageCodeOrder){
    // ....
    return $strings;
}

$strings = magicStringOrder($strings, array('EN', 'IT') );

$strings = array(
   array("languageCode" => "EN",  "string" => "hello"),
   array("languageCode" => "IT",  "string" => "ciao"),
   array("languageCode" => "ES",  "string" => "hola"),
   array("languageCode" => "CHS", "string" => "您好"),
);

There is magicStringOrder?

I now know that it is a simple problem to solve with a few loops. I would need a very fast function (it is called many times, with large array)

Upvotes: 2

Views: 92

Answers (2)

Jonny 5
Jonny 5

Reputation: 12389

Another idea without php sort functions:

// sort by cmp $arr[$magic_key] <-> arr $magic_order
function magicSort($arr, $magic_key="", $magic_order = array())
{
  $sorted = array();
  foreach($magic_order AS $v) {
    foreach($arr AS $k2 => $v2) {
      if($v===$v2[$magic_key]) {
        $sorted[] = $v2;
        unset($arr[$k2]);
      }
    }
  }

  // attach what's left
  return array_merge($sorted, $arr);
}

Test it at eval.in (link expires soon)

$strings = array(
   array("languageCode" => "ES",  "string" => "hola"),
   array("languageCode" => "EN",  "string" => "hello"),
   array("languageCode" => "IT",  "string" => "ciao"),
   array("languageCode" => "CHS", "string" => "??"),
);

print_r(magicSort($strings, "languageCode", array("EN", "IT")));

outputs to:

Array
(
    [0] => Array
        (
            [languageCode] => EN
            [string] => hello
        )

    [1] => Array
        (
            [languageCode] => IT
            [string] => ciao
        )

    [2] => Array
        (
            [languageCode] => ES
            [string] => hola
        )

    [3] => Array
        (
            [languageCode] => CHS
            [string] => 您好
        )

)

$magic_order can also be empty. If so, the array is just reindexed. Arrays with values, that don't exist in $magic_order are shifted down and order of those is maintained.

Not sure, if that's exactly what you need.

Upvotes: 2

acontell
acontell

Reputation: 6922

If it's not a problem to give a weight to a language, the sorting becomes much easier and therefore quicker.

You can use asort to sort the array based on the $languageCodeOrder stored weights. If a language it's not present in the $languageCodeOrder its weight becomes 0 and goes towards the end of the ordered array.

The final order of the array will be from high weight to low. That is: if EN has a weight of 1 it will appear in the array after IT that has 2.

$strings = array(
    array("languageCode" => "ES", "string" => "hola"),
    array("languageCode" => "EN", "string" => "hello"),
    array("languageCode" => "IT", "string" => "ciao"),
    array("languageCode" => "CHS", "string" => "您好"),
);

function magicStringOrder(array $strings, array $languageCodeOrder) {
    uasort($strings, function($a,$b) use ($languageCodeOrder) {
        $val_a = (isset($languageCodeOrder[$a["languageCode"]])) ? $languageCodeOrder[$a["languageCode"]] : 0;
        $val_b = (isset($languageCodeOrder[$b["languageCode"]])) ? $languageCodeOrder[$b["languageCode"]] : 0;

        return $val_b - $val_a;
    });
    return $strings;
}

$strings_ordered = magicStringOrder($strings, array('EN' => 1, 'IT' => 2, 'ES' => 3, 'CHS' => 4));

print_r($strings_ordered);

If the arrays are big, it's better to rely on PHP sort algorithms rather than trying to implement custom ones.

Feel free to modify anything in the algorithm (order or whatever).

Upvotes: 1

Related Questions