Search code examples
phparray-reduce

Array reduce with associative array


I have an array like this

 $filter_array = Array
    (
        [0] => Array
            (
                [fv_id] => 1
                [fv_value] => Red
                [filter_id] => 1
                [filter_name] => Color
            )

        [1] => Array
            (
                [fv_id] => 2
                [fv_value] => Blue
                [filter_id] => 1
                [filter_name] => Color
            )

    )

I would like to reduce the array by having filter_name and filter_id on top of array which is similar for all arrays.

$newArray = array_reduce($filter_array,function($carry,$item){

            $allFilterValues[] = array(
                'fv_id' => $item['fv_id'],
                'fv_value' => $item['fv_value'],
            );

             $formated_array = array(
                'filter_id' => $item['filter_id'],
                'filter_name' => $item['filter_name'],
                'filter_values' => $allFilterValues
            );
            return $formated_array;
        });

But I am just getting the last array iterations value on filter_values

Array
(
    [filter_id] => 1
    [filter_name] => Color
    [filter_values] => Array
        (
            [0] => Array
                (
                    [fv_id] => 2
                    [fv_value] => Blue
                )

        )

)

But I want the array be like this.

Array
(
    [filter_id] => 1
    [filter_name] => Color
    [filter_values] => Array
        (
                [0] => Array
                (
                    [fv_id] => 1
                    [fv_value] => Red
                ),

                [1] => Array
                (
                    [fv_id] => 2
                    [fv_value] => Blue
                )

        )

)

Solution

  • On each iteration of array_reduce callback function must return current $carry value:

    $newArray = array_reduce($filter_array,function($carry,$item){
        // create key so as to distinct values from each other
        $key = $item['filter_id'] . '-' . $item['filter_name'];
    
        // check if created key exists in `$carry`, 
        // if not - we init it with some data
        if (empty($carry[$key])) {
            $carry[$key] = [
                'filter_id' => $item['filter_id'],
                'filter_name' => $item['filter_name'],
                'filter_values' => []
            ];
        }
    
        // add values to `filter_values`
        $carry[$key]['filter_values'][] = [
            'fv_id' => $item['fv_id'],
            'fv_value' => $item['fv_value'],
        ];
    
        return $carry;
    }, []);
    
    // if you want to reindex `$newArray` from 0:
    $newArray = array_values($newArray);
    

    Update: if and only if in your $filter_array values of 'filter_id' and 'filter_name' are always the same you can simplify your code:

    $newArray = [];
    $first = true;
    foreach ($filter_array as $item) {
        if ($first) {
            $first = false;
            $newArray = [
                'filter_id' => $item['filter_id'],
                'filter_value' => $item['filter_name'],
                'filter_values' => []
            ];
        }
    
        $newArray['filter_values'][] = [
            'fv_id' => $item['fv_id'],
            'fv_value' => $item['fv_value'],
        ];
    }
    echo'<pre>',print_r($newArray),'</pre>';