PHP sort positions with null values but maintain structure

Linesofcode :

I'd like to sort an array with values that may or not exist in the database and the order structure should be respected.

Structure by default (positions from 1 to 5):

Amazon | Google | Ebay | Microsoft | Alibaba

This structure is initialized in PHP this way:

$data = 
[
    'Amazon'    => ['position' => null],
    'Google'    => ['position' => null],
    'Ebay'      => ['position' => null],
    'Microsoft' => ['position' => null],
    'Alibaba'   => ['position' => null]
];

Important: The positions stored in the database are always equal or bigger than 1.

Lets say Google has the position 1 and Alibaba 4 in the database:

$data['Google']['position'] = $fromDb->google->position; // 1
$data['Alibaba']['position'] = $fromDb->alibaba->position; // 4

If I sort the array using the array_multisort function as follows:

$sort = [];

foreach ($data as $key => $value)
    $sort[$key] = $value['position'];

array_multisort($sort, SORT_ASC, $data);

Output:

Array
(
    [Amazon] => 
    [Ebay] => 
    [Microsoft] => 
    [Google] => 1
    [Alibaba] => 4
)

Desired output:

Array
(
    [Google] => 1
    [Amazon] => 2
    [Ebay] => 3
    [Alibaba] => 4
    [Microsoft] => 5
)
deceze :

Filling in the missing values before doing a simple usort:

$data = [
    'Amazon'    => ['position' => null],
    'Google'    => ['position' => 1],
    'Ebay'      => ['position' => null],
    'Microsoft' => ['position' => null],
    'Alibaba'   => ['position' => 4]
];

// Find existing positions.
$positions = array_filter(array_column($data, 'position'));
$i = 1;

foreach ($data as &$comp) {
    if ($comp['position']) {
        // Element already has a position, skip to next one.
        continue;
    }
    while (in_array($i, $positions)) {
        // Increment the counter until we find a value not yet taken.
        $i++;
    }
    // Assign the counter value to the current element.
    $comp['position'] = $i++;
}
unset($comp);

// Sort all values with a simple comparison function.
uasort($data, function ($a, $b) { return $a['position'] <=> $b['position']; });

Somewhat fancier:

// Compute the *missing* positions by subtracting the existing positions
// (extracted via array_column) from the set of possible positions
// (generated with range()).
$positions = array_diff(range(1, count($data)), array_filter(array_column($data, 'position')));

// Apply the missing positions to the array elements in order
// (taking positions off the beginning with array_shift).
array_walk($data, function (&$i) use (&$positions) {
    if (!$i['position']) {
        $i['position'] = array_shift($positions);
    }
});

// Sort all values with a simple comparison function.
uasort($data, function ($a, $b) { return $a['position'] <=> $b['position']; });

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=15507&siteId=1