Как удалить значения с помощью массива черного списка, а затем уменьшить оставшиеся значения, чтобы устранить пробелы? - PullRequest
0 голосов
/ 09 июля 2020

Этот вопрос в основном является расширением моего предыдущего вопроса:

Как вычесть значение из массива, но все еще в позиции

У меня есть входной массив массивов. Значения в каждом подмассиве всегда состоят из значений, начинающихся с 0, и без каких-либо пробелов значения увеличиваются на единицу. Однако значения не обязательно в порядке, и мне нужно сохранить этот порядок при выполнении моего необходимого logi c.

Затем у меня есть черный список значений, которые я sh удаляю из всех подмассивов. Любое исходное значение подмассива, которое существует в массиве черного списка, должно быть удалено.

Пример входного массива массивов:

$arrays = [
    [0, 3, 10, 5, 6, 9, 2, 7, 1, 4, 8, 11],
    [0, 1, 2, 3],
    [0, 5, 2, 4, 3, 1],
    [0, 1, 3, 2]
];

Пример массива черного списка:

$deletes = [3, 5];

Мое желаемое вывод:

[
    [0, 8, 4, 7, 2, 5, 1, 3, 6, 9],
    [0, 1, 2],
    [0, 2, 3, 1],
    [0, 1, 2],
]

Все оставшиеся значения больше 3 уменьшаются на 1, а значения больше 5 уменьшаются на 2, так как я удалил 2 чисел.

Если все числа в данном подмассиве меньше, чем все числа в массиве черного списка, то никаких изменений для этого подмассива не требуется.

У меня здесь попытка кодирования https://3v4l.org/lX2MP, но я застрял при возврате их значений. Все значения массива были объединены.

Ответы [ 2 ]

1 голос
/ 09 июля 2020

Я собираюсь немного изменить ваши 2-й, 3-й и 4-й подмассивы, чтобы лучше продемонстрировать поведение.

Опираясь на одну из техник в моем ответе на ваш предыдущий вопрос, я фактически просто упаковываю код logi c в дополнительном l oop array_map().

array_diff() используется для мгновенного уничтожения любых значений во входном массиве, которые соответствуют значениям удаления. Затем array_reduce() используется для оставшихся значений входного массива для итерации и уменьшения целых чисел, любые сгенерированные устраняют пробелы.

Внутри array_reduce() вы увидите $value > $item. Это сравнение вернет true или false. Когда в качестве числа используется логическое значение, true становится 1, а false становится 0. По сути, я вычитаю 0 или 1 из $value в зависимости от того, как каждое значение $deletes сравнивается с заданным $value.

В качестве конкретного примера c при обработке 10, 10 больше, чем 3, поэтому оно становится 9, а 10 больше 5, поэтому 9 становится 8.

Все это делается без требуется предварительно отсортировать данные.

Код: ( Демо )

$arrays = [[0, 3, 10, 5, 6, 9, 2, 7, 1, 4, 8, 11], [0, 1, 2, 3], [0, 5, 2, 4, 3, 1], [0, 1, 3, 2]];
$deletes = [3, 5];

var_export(
    array_map(
        function($array) use ($deletes) {
            $result = [];
            foreach (array_diff($array, $deletes) as $value) {
                $result[] = array_reduce(
                    $deletes,
                    function ($carry, $item) use ($value) {
                        return $carry - ($value > $item);
                    },
                    $value
                );
            }
            return $result;
        },
        $arrays
    )
);

Вот альтернатива, которая ведет себя так же, но не зависит от функционального программирования так много: ( Демо )

foreach ($arrays as $index => $array) {
    $filtered = array_diff($array, $deletes);  // destroy blacked values
    foreach ($filtered as $value) {
        $originalValue = $value;
        foreach ($deletes as $delete) {
            $value -= $originalValue > $delete; // reduce to eliminate gaps
        }
        $result[$index][] = $value;
    }
}

var_export($result);

Вывод (для любого фрагмента):

array (
  0 => 
  array (
    0 => 0,
    1 => 8,
    2 => 4,
    3 => 7,
    4 => 2,
    5 => 5,
    6 => 1,
    7 => 3,
    8 => 6,
    9 => 9,
  ),
  1 => 
  array (
    0 => 0,
    1 => 1,
    2 => 2,
  ),
  2 => 
  array (
    0 => 0,
    1 => 2,
    2 => 3,
    3 => 1,
  ),
  3 => 
  array (
    0 => 0,
    1 => 1,
    2 => 2,
  ),
)
1 голос
/ 09 июля 2020

Чтобы удалить числа из массива и вычесть количество из текущего числа в исходном массиве с количеством чисел меньше, чем оно в selectedDeletedNumbers, вы можете:

  • Сортировать массив selectedDeletedNumbers.

  • Выполните итерацию по исходному массиву и используйте binary search, чтобы получить количество чисел меньше текущего числа в исходном массиве и вычтите его позже.

  • Если текущий номер присутствует в selectedDeletedNumbers, сбросьте их.

  • Примените вышеуказанную операцию к каждому отдельному подмассиву .

Фрагмент:

<?php

function subtract(&$arr,$selectedDeletedNumbers){ // pass by reference to edit the same copy of the array
    foreach($arr as $index => $val){
        $low = 0;$high = count($selectedDeletedNumbers) - 1;
        $equal_found = false;
        while($low <= $high){
            $mid = intval(($low + $high) / 2);
            if($selectedDeletedNumbers[$mid] > $val){
                $high = $mid - 1;
            }else if($selectedDeletedNumbers[$mid] < $val){
                $low = $mid + 1;
            }else{
                $equal_found = true;
                unset($arr[$index]); // if equal value, delete it as it your need
                break;
            }
        }
    
        if(!$equal_found){
            $arr[$index] -= $low; // delete the offset till where it is greater among your $selectedDeletedNumbers
        }
    }
}

$selectedDeletedNumbers = [3,5];
sort($selectedDeletedNumbers); // sort to be apply binary search later
$arr = [[0, 3, 10, 5, 6, 9, 2, 7, 1, 4, 8, 11], [0, 1], [0, 1], [0, 1]];

foreach($arr as &$val){ // pass by reference to edit the same copy of the array
    subtract($val,$selectedDeletedNumbers); 
}

print_r($arr);

Демо: https://3v4l.org/RMh5U

Если вы хотите последовательно переиндексировать числа, сделайте array_values() для каждого отдельного подмассива в конце.

...