umsortiert: Sortieren mit "ungewöhnlichen" Konventionen

Hi,

Ich möchte ein Array nach festgelegten Konventionen sortieren:
1. Elementreihenfolge sollte soweit wie möglich beibehalten werden
2. Scalar, NULL sowie rein numerisch* indizierte Array Elemente sollen vor  anderen komplexen Elementen sortiert werden

*Test auf vorhandensein des Elements mit den Index 0 im Array(Access) ist per Konvention hinreichend genau

Die Lösung die mir bisher dazu eingefallen ist liefert, soweit ich das bisher getestet habe, die gewünschten Ergebnisse.
Allerdings erscheint mir die Lösung recht krude (sortiert wird zb. ein garantiert sortiertes Array!) und CPU lastig.

Wie könnte man das effizienter bzw. eleganter gestalten?

  
function sort($input)  
{  
    $result = array();  
    $keys   = array_keys($input);  
    $values = array_values($input);  
    $index  = array_keys($values);  
    $sorter = function($a, $b) use($values) {  
        $va = $values[$a];  
        $vb = $values[$b];  
        $wa = is_scalar($va) || is_null($va) || empty($va) || array_key_exists(0, $va);  
        $wb = is_scalar($vb) || is_null($vb) || empty($vb) || array_key_exists(0, $vb);  
        return $wa !== $wb ? $wb - $wa : $a - $b;  
    };  
    if (usort($index, $sorter)) {  
        foreach ($index as $order) {  
            $result[$keys[$order]] = $values[$order];  
        }  
    }  
    return $result;  
}  
  
$input = array(  
    'a' => 'A',  
    'b' => array(1 => 'B'),  
    'c' => 'C',  
    'd' => array('D'),  
    'e' => array('E'),  
    'f' => array('F' => 'F'),  
    'g' => FALSE,  
    'h' => (object)array('H'=>'H'),  
    'i' => NULL,  
    'j' => array(),  
    'k' => 'K',  
);  
  
$output       = sort($input);  
$currentKeys  = implode('', array_keys($output));  
$expectedKeys = 'acdegijkbfh';  
  
printf('Erwartete  Ordnung "%s"', $expectedKeys);  
if ($currentKeys === $expectedKeys) {  
    echo ' ist gegeben';  
} else {  
    echo ' ist nicht gegeben!', PHP_EOL;  
    printf('Gelieferte Ordnung "%s"', $currentKeys);  
}  

  1. Hallo,

    1. Elementreihenfolge sollte soweit wie möglich beibehalten werden

    Du möchtest einen stabilen Sortieralgorithmus verwenden. Daraus folgt, dass Du die in PHP eingebauten Sortierfunktionen *nicht* verwenden kannst. Ich zitiere aus dem Handbuch:

    <zitat>
        PHP has several functions that deal with sorting arrays, and this
        document exists to help sort it all out.

    - [...]
        - If any of these sort functions evaluates two members as equal then
          the order is undefined (the sorting is not stable).
    </zitat>

    1. Scalar, NULL sowie rein numerisch* indizierte Array Elemente sollen vor  anderen komplexen Elementen sortiert werden

    Teile Dein Array in Teilarrays auf. Kombiniere nach dem Sortieren der Teilarrays diese in der von Dir gewünschten Reihenfolge.

    Wie könnte man das effizienter bzw. eleganter gestalten?

    Implementiere einen effizienten und stabilen Sortieralgorithmus, zum Beispiel Mergesort, den Du zum Sortieren Deiner Teilarrays verwendest.

    Freundliche Grüße

    Vinzenz

    1. Hallo Vinzenz,

      Teile Dein Array in Teilarrays auf. Kombiniere nach dem Sortieren der Teilarrays diese in der von Dir gewünschten Reihenfolge.

      Das war ein guter Hinweis, verteilen und anschliessendes zusammensetzen ist tatsächlich eine recht einfache Lösung. Sollte auch effizienter sein.

        
      function sort($input)  
      {  
          // 0 = tail, 1 = head  
          $parts = array(array(), array());  
          foreach ($input as $key => $value) {  
              $target = is_scalar($value) || is_null($value) || empty($value) || array_key_exists(0, $value);  
              $parts[$target][$key] = $value;  
          }  
          return array_merge($parts[1], $parts[0]);  
      }