Как заказать массив «зебра», чтобы каждый ключ имел альтернативное значение (1, 0) - PullRequest
0 голосов
/ 22 января 2020

Если у вас есть этот массив PHP:

$args = array(
    'a' => array(
        'zebra' => 1,
    ),
    'b' => array(
        'zebra' => 0,
    ),
    'c' => array(
        'zebra' => 0,
    ),
    'd' => array(
        'zebra' => 0,
    ),
    'e' => array(
        'zebra' => 1,
    ),
);

Есть ли способ алгоритмически изменить порядок этого массива по значению ключа "зебра", но вместо того, чтобы быть "возрастающим" (0 , 0,0,1,1), они будут чередоваться (0,1,0,1,0).

Так что, используя приведенный выше пример, желаемый готовый массив будет выглядеть так:

$ordered_args = array(
    'b' => array(
        'zebra' => 0,
    ),
    'a' => array(
        'zebra' => 1,
    ),
    'c' => array(
        'zebra' => 0,
    ),
    'e' => array(
        'zebra' => 1,
    ),
    'd' => array(
        'zebra' => 0,
    ),

);

Любые дополнительные дубликаты должны быть добавлены в конец, поэтому в решении должны быть предусмотрены другие массивы, например, со значениями зебры, такими как (1,1,1,1,0,0), что приведет к (0 , 1,0,1,1,1)

Я просто не могу понять это!

Редактировать: я пытался сделать это с помощью usort, через это похоже, но другой, вопрос , и ответ был отрицательный, поэтому я ищу программное решение c (без usort).

Ответы [ 4 ]

0 голосов
/ 22 января 2020

Вот решение, использующее array_map после захвата 1 и 0 в отдельных массивах:

$args0 = array_filter($args, function ($arg) {
  return $arg['zebra'] === 0;
});
$args1 = array_filter($args, function ($arg) {
  return $arg['zebra'] === 1;
});

$result = array_merge(...array_map(static function ($arg0Key, $arg1Key) use ($args0, $args1) {
  if ($arg0Key !== null) {
    $result[$arg0Key] = $args0[$arg0Key];
  }
  if ($arg1Key !== null) {
    $result[$arg1Key] = $args1[$arg1Key];
  }
  return $result;
}, array_keys($args0), array_keys($args1)));

print_r($result);

Демонстрация: https://3v4l.org/sfqeq

Примечание: использование двух array_filter для разделения значений выглядит красиво, но повторяется $args дважды; предпочитаю простой l oop, если начальный массив может быть несколько большим. Это не важная часть ответа.

0 голосов
/ 22 января 2020

Ну, вы можете собрать все 0 s 'в одном массиве и все 1 s' в другом массиве и просто добавить их в новый массив попеременно с логической проверкой flag.

Псевдокод:

ones = []
zeroes = []

for($args as key => value)
    value['key'] = key // to preserve the key as well for later restoration
    if(value['zebra'] == 1)
       ones.push(value)
    else 
       zeroes.push(value)


result = []
flag = true // to decide to pop from ones or zeroes


while(sizeof(ones) > 0 || sizeof(zeroes) > 0){
    if(sizeof(ones) == 0 || flag === false){
        element = zeroes.pop()
        result[element['key']] = ['zebra' => element['zebra']]
    }else if(sizeof(zeroes) == 0 || flag){
        element = ones.pop()
        result[element['key']] = ['zebra' => element['zebra']]
    }   

    flag = !flag // to alternately add from either arrays
}
0 голосов
/ 22 января 2020

Та же идея разделить ввод на 1 и 0, а затем вывести 0 и 1, пока есть что-то, что нужно вывести. Каждый раз, когда вы выводите значение, массив уменьшается, это продолжается до тех пор, пока оба списка не станут пустыми, поэтому должны справляться с несбалансированными списками ...

$temp = [ 0 => [], 1 => []];

foreach($args as $key=>$value){
    $temp[$value['zebra']][] = $key;
}

$output = [];
while ( !empty($temp[0]) || !empty($temp[1]) )   {
    if ( !empty($temp[0]) )   {
        $next = array_shift($temp[0]);
        $output [$next] = $args[$next];
    }
    if ( !empty($temp[1]) )   {
        $next = array_shift($temp[1]);
        $output [$next] = $args[$next];
    }
}
0 голосов
/ 22 января 2020

Я могу предложить вам использовать деконструкцию с количеством сравнений.

На первом шаге вы можете собрать все индексы с zebra = 1 и с zebra = 0:

$zeros = [];
$ones = [];

foreach($args as $let=>$arg){
    if ($arg['zebra'] === 1) {
        $ones[] = $let;
    } else if ($arg['zebra'] === 0) {
        $zeros[] = $let;
    }
}

А теперь Вы можете создать результирующий массив, например:

if(abs(count($zeros) - count($ones)) === 1) {    // if their difference equal to 1
    if (count($ones) > count($zeros)){           // if $ones is bigger
        foreach($zeros as $ind=>$let){ 
            $res[$ones[$ind]] = ['zebra' => 1];
            $res[$let]        = ['zebra' => 0];  
            $tmp = $ind;
        } 
        $res[$ones[$tmp+1]] = ['zebra' => 1];
    } else if (count($ones) < count($zeros)){      // if $zeros is bigger
        foreach($ones as $ind=>$let){ 
            $res[$zeros[$ind]] = ['zebra' => 0];
            $res[$let]        = ['zebra' => 1];  
            $tmp = $ind;
        } 
        $res[$zeros[$tmp+1]] = ['zebra' => 0];
    }
}

Вывод:

Array
(
    [b] => Array
        (
            [zebra] => 0
        )

    [a] => Array
        (
            [zebra] => 1
        )

    [c] => Array
        (
            [zebra] => 0
        )

    [e] => Array
        (
            [zebra] => 1
        )

    [d] => Array
        (
            [zebra] => 0
        )

)

Демо

Если вам нужен результат в случае (1,0,1,0,0) использовать следующий конструктор:

    if (count($ones) > count($zeros)){
        foreach($ones as $ind=>$let){ 
            if (isset($zeros[$ind])) $res[$zeros[$ind]] = ['zebra' => 0]; 
            $res[$let]        = ['zebra' => 1];  
        }  
    } else if (count($zeros) > count($ones)){
        foreach($zeros as $ind=>$let){ 
            $res[$let]        = ['zebra' => 0];  
            if (isset($ones[$ind])) $res[$ones[$ind]] = ['zebra' => 1]; 
        }  
    }

Вывод:

Array
(
    [b] => Array
        (
            [zebra] => 0
        )

    [a] => Array
        (
            [zebra] => 1
        )

    [d] => Array
        (
            [zebra] => 0
        )

    [c] => Array
        (
            [zebra] => 1
        )

    [e] => Array
        (
            [zebra] => 0
        )

)

Демо

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...