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 )