Skip to content
Advertisement

PHP associative array sorting by previous value

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
)

Demo on 3v4l.org

User contributions licensed under: CC BY-SA
3 People found this is helpful
Advertisement