Можно ли сократить код?

130
26 января 2021, 12:30

Меня интересует можно ли сократить повторяющуюся проверку условий:

Дано: массив с товарами и 3 статусами прямо в записи (Новинка, Акция, Топ продаж) (так надо).

Нужно: распределить товары по их статусам.

Делаю:

// Получаем товары
$result = get_array(); //не суть важно 
// Статичные фильтры заполняем сразу
$filter_data = [
    "is_new" => [
        "title" => getval("STR_STATUS_NEW"),
        "products" => []
    ],
    "is_act" => [
        "title" => getval("STR_STATUS_ACT"),
        "products" => []
    ],
    "is_top" => [
        "title" => getval("STR_STATUS_TOP"),
        "products" => []
    ]
];
// Заполняем по старинке через цикл
foreach($result as $filter){
    if(!empty($filter["is_new"])){
        $filter_data["is_new"]["products"][$filter["id"]] = $filter["id"];
    }
    if(!empty($filter["is_act"])){
        $filter_data["is_act"]["products"][$filter["id"]] = $filter["id"];
    }
    if(!empty($filter["is_top"])){
        $filter_data["is_top"]["products"][$filter["id"]] = $filter["id"];
    }
    unset($filter);
}

Хочу: обойтись без цикла

Пытаюсь:

// Проверяем наличие ключа $filter_data у каждой записи
function checkArray($product,$filters){
    foreach($filters as $key => $value){
        if(!empty($product[$key])){
            $filters[$key]["products"][$product["id"]] = $product["id"];
        }
        unset($key,$value);
    }
}
// Тестим
foreach($result as $filter){
    $filter_data = array_map("checkArray",$filter,$filter_data);
    unset($filter);
}

Итог:

Invalid argument supplied for foreach()

Потому что мы потеряли ключи у массива $filter_data? (нигде не нашел, что array_map сбрасывает ключи)

Вопрос: как быть и нужно ли делать что-то подобное?

UPD

Коллега подсказал решение - использовать array_reduce

$filter_data = array_reduce(
    $result,
    function ($filter_data,$product) {
        foreach($filter_data as $key => $value){
            if(!empty($product[$key])){
                $filter_data[$key]["products"][$product["id"]] = $product["id"];
            }
            unset($key,$value);
        }
        return $filter_data;
    },
    $filter_data
);

Однако громоздкая анонимная функция сбивает меня с толку) Понятно, что ее можно вынести, но нужно ли? Хотелось бы также увидеть "правильные" решения. Я просто впервые пытаюсь писать такое.

Answer 1

Никогда не нужно прыгать через голову. Казалось бы, задача простая и понятная - запихнуть три условия в цикл. И откуда в решении появились функции, синтаксический сахар для циклов и прочая требуха. почему нельзя тупо схлопнуть три условия в цикл, и на этом остановиться?

foreach($result as $product) {
    foreach ($filter_data as $key => $filter) {
        if(!empty($product[$key])){
            $filter_data[$key]["products"][$product["id"]] = 1;
        }
    }
}

Я убрал $product["id"] из значений, поскольку в дублировании ключа не вижу смысла

Да, и на всякий случай поясню очевидное. Всякие магические заклинания типа "array_filter", "array_reduce" и прочий синтаксический сахар не являются некоей волшебной заменой циклов. Это те же самые циклы, только в красивой обертке. Не существует магического способа перебрать все элементы массива без цикла. Когда страус втыкает голову в песок и перестает видеть хищника, это не значит, что хищник перестает видеть страуса. Когда мы упаковываем цикл в вызов функции, он не исчезает.

В общем, если покороче, то написав внутри array_filter внутри foreach вы получаете тот же самый цикл в цикле.

READ ALSO
laravel 5.8 и morphMany

laravel 5.8 и morphMany

В документации описано как должны выглядить модели как из них получать, а вот не показанно как их записывать, я пробовал через attach но позже...

115
Привязка соц сети к аккаунту php

Привязка соц сети к аккаунту php

Как реализовать привязку соц сети, например ютуб к аккаунту пользователя php делать отдельную таблицу, где хранить данные из соц сети и id пользователя...

113
Регулярное выполнение задачи

Регулярное выполнение задачи

У меня есть игровой бот, там есть эвенты во время которых людям нужно ждать некоторое время (от 10 секунд до нескольких минут)Чтобы в это время...

121