I have the following array that I’m trying to sort. The value is where the key should come after in the final output array.
$main = array(
'lorem' => 'lorem',
'ipsum' => 'duis',
'sit' => 'adipiscing',
'duis' => 'sit',
'amet' => 'elit',
'consectetur' => 'lorem',
'adipiscing' => 'consectetur',
'eiusmod' => 'ipsum',
'labore' => 'eiusmod',
'dolore' => 'labore',
'magna' => 'dolore',
'incididunt' => 'magna',
'tempor' => 'incididunt',
'sed' => 'tempor',
'elit' => 'sed',
'aliqua' => 'amet'
);
The final output would be like this.
$final = array(
'lorem' => 'lorem',
'consectetur' => 'lorem',
'adipiscing' => 'consectetur',
'sit' => 'adipiscing',
'duis' => 'sit',
'ipsum' => 'duis',
'eiusmod' => 'ipsum',
'labore' => 'eiusmod',
'dolore' => 'labore',
'magna' => 'dolore',
'incididunt' => 'magna',
'tempor' => 'incididunt',
'sed' => 'tempor',
'elit' => 'sed',
'amet' => 'elit',
'aliqua' => 'amet'
);
I’ve been trying to wrap my head around an appropriate approach but I seem to be taking myself down the wrong paths. I keep ending up with only some of the elements following the correct rules. How would you tackle this? I tried looping, splicing and searching in many ways with no luck.
Edit: uncleaned attempt
$final = array();
$main = array_merge($current_word_types, $word_types);
foreach ($main as $id => $previousWord) {
$final[$id] = $previousWord;
if ($id === $previousWord) {
continue;
}
if (isset($word[$id])) {
continue;
}
$previousKey = array_search($previousWord, $main );
$previousKeyIndex = array_search($previousWord, array_keys($main ));
$final = array_slice($final, 0, $previousKeyIndex, true) +
array($previousKey => $main [$previousKey]) +
array_slice($word, $previousKeyIndex, NULL, true);
}
Edit 2: Here are the master lists I built $main
from
// master ordering list
$word_types = array(
'lorem' => 'lorem',
'ipsum' => 'lorem',
'sit' => 'ipsum',
'duis' => 'sit',
'amet' => 'duis',
'consectetur' => 'amet',
'adipiscing' => 'consectetur',
'eiusmod' => 'adipiscing',
'labore' => 'eiusmod',
'dolore' => 'labore',
'magna' => 'dolore',
'incididunt' => 'magna',
'tempor' => 'incididunt',
'sed' => 'tempor',
'elit' => 'sed',
'aliqua' => 'elit'
);
// items that ended up getting special order treatment due
// someone reordering the words so the $main output to needs
// to compensate for this. (this could end up empty at times)
$current_word_types = array(
'lorem' => 'lorem',
'consectetur' => 'lorem',
'duis' => 'consectetur',
'amet' => 'duis',
'elit' => 'amet'
);
Advertisement
Answer
Here’s a function that will sort the array the way you want. It is based on @deceze algorithm (described in the comments to the question), using array_diff
to find the key which is not also a value, and then iterating back through the array until the key matches the value at that key:
function sorter($array) {
// find the key which doesn't have a matching value
$unique = array_diff(array_keys($array), $array);
$key = reset($unique);
$value = $array[$key];
$result = array($key => $value);
// follow the values backwards until the key matches the value
while ($key != $value) {
$key = $array[$key];
$value = $array[$key];
$result = array($key => $value) + $result;
}
return $result;
}
Output of print_r(sorter($main))
for your data:
Array
(
[lorem] => lorem
[consectetur] => lorem
[adipiscing] => consectetur
[sit] => adipiscing
[duis] => sit
[ipsum] => duis
[eiusmod] => ipsum
[labore] => eiusmod
[dolore] => labore
[magna] => dolore
[incididunt] => magna
[tempor] => incididunt
[sed] => tempor
[elit] => sed
[amet] => elit
[aliqua] => amet
)