Задать вопрос
  • Как отфильтровать по вложенной коллекции laravel?

    alexey-m-ukolov
    @alexey-m-ukolov Куратор тега PHP
    Красиво у каждого своё, плюс оно зависит от нюансов проекта.
    При условии, что мы не знаем заранее количество ключей lvlX, я бы написал так:
    // Если нужно полностью удалить элемент, внутри которого есть хотя бы один нулевой lvl
    array_filter(
        $a,
        function (array $item): bool {
            foreach ($item as $key => $value) {
                if (preg_match('~^lvl\d+$~', $key) === 1 && ($value['count'] === 0 || $value['min'] === 0 || $value['max'] === 0)) {
                    return false;
                }
            }
    
            return true;
        }
    );
    
    // Если нужно удалять только сами нулевые lvl
    array_map(
        function (array $item): array {
            return array_filter(
                $item,
                function ($value, string $key): bool {
                    return preg_match('~^lvl\d+$~', $key) !== 1 || ($value['count'] !== 0 && $value['min'] !== 0 && $value['max'] !== 0);
                },
                ARRAY_FILTER_USE_BOTH
            );
        },
        $a
    );

    Код нужно адаптировать в зависимости от того, где там у вас реально коллекция, а где массив, но это уже тривиальная задача.
    Ну и здесь предполагается, что структура каждого lvl фиксированная, то есть там всегда есть указанные ключи, чтобы не загромождать код проверками isset().

    Ну а самое красивое, на мой вкус, переделать структуру на более адекватную:
    [
        [
            'name' => 'Alex',
            'levels' => [
                ['index' => 1, 'count' => 5, 'min' => 12, 'max' => 5],
                ['index' => 2, 'count' => 0, 'min' => 5, 'max' => 7],
                ['index' => 3, 'count' => 18, 'min' => 0, 'max' => 8],
            ],
        ],
        [
            'name' => 'Igor',
            'levels' => [
                ['index' => 1, 'count' => 5, 'min' => 12, 'max' => 5],
                ['index' => 2, 'count' => 0, 'min' => 5, 'max' => 7],
                ['index' => 3, 'count' => 18, 'min' => 0, 'max' => 8],
            ],
        ]
    ];
    Тогда и код фильтрации будет простым и понятным.

    Если же ключи lvl1, lvl2 и lvl3 фиксированные, то, на мой вкус, лучше их захардкодить, это тоже значительно упростит жизнь в будущем, когда вы этот код откроете через пару лет и будете пытаться вспомнить что это за нагромождение из map, filter и регулярок.
    Ответ написан
    2 комментария
  • Laravel найти в коллекциях по ключу и объединить в новую коллекцию?

    grantur5707
    @grantur5707
    Full Stack Web Developer
    use Illuminate\Support\Collection;
    
    $collection1 = collect([
        [
            "имя1" => "John",
            "объем1" => "100",
            "мусор" => "x"
        ],
        [
            "имя1" => "Jane",
            "объем1" => "200",
            "мусор" => "y"
        ]
    ]);
    
    $collection2 = collect([
        [
            "имя2" => "John",
            "объем2" => "300",
            "мусор" => "x"
        ],
        [
            "имя2" => "Jane",
            "объем2" => "400",
            "мусор" => "z"
        ]
    ]);
    
    function normalizeKeys(Collection $collection, $nameKey, $volumeKey)
    {
        return $collection->map(function ($item) use ($nameKey, $volumeKey) {
            return [
                'name' => $item[$nameKey] ?? null,
                'volume' => $item[$volumeKey] ?? null,
            ];
        });
    }
    
    $normalized1 = normalizeKeys($collection1, 'имя1', 'объем1');
    $normalized2 = normalizeKeys($collection2, 'имя2', 'объем2');
    
    $result = $normalized1->map(function ($item1) use ($normalized2) {
        $match = $normalized2->firstWhere('name', $item1['name']);
        
        return [
            'name' => $item1['name'],
            'volume1' => $item1['volume'],
            'volume2' => $match['volume'] ?? null,
        ];
    });
    Ответ написан
    1 комментарий