Sortieren mit "ungewöhnlichen" Konventionen
umsortiert
- php
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);
}
Hallo,
- 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>
- 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
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]);
}