-1

I have this array:

$array_1 = [
    ['model' => 'iPhone 12', 'grade' => 'A', 'price' => '100'],
    ['model' => 'iPhone 12', 'grade' => 'A', 'price' => '95'],
    ['model' => 'iPhone 12', 'grade' => 'B', 'price' => '85'],
    ['model' => 'iPhone 12', 'grade' => 'C', 'price' => '75'],
];

I would like to merge the values of the grade and price into its own key value pair and make it look like this:

$array_2 = [
    ['model' => 'iPhone 12', 'A' => '100'],
    ['model' => 'iPhone 12', 'A' => '95'],
    ['model' => 'iPhone 12', 'B' => '85'],
    ['model' => 'iPhone 12', 'C' => '75']
];

I would then like to sort the data by looking at the arrays with similar grades and keep only the array with the lowest price. So in the end the array should look something like this:

$array_3 = [
    ['model' => 'iPhone 12', 'A' => '95'],
    ['model' => 'iPhone 12', 'B' => '85'],
    ['model' => 'iPhone 12', 'C' => '75']
];

How can I go about doing this?

mickmackusa
  • 43,625
  • 12
  • 83
  • 136

2 Answers2

1

To find the minimum A price in your second array, you would have to filter out the items that have such a key A to begin with, only at that point, you don't really know that you are looking for the key A in the first place ...

This is easier, if you do it the other way around - filter the items so that only those with the minimum prices remain, and convert those to your desired format after.

$array_2 = [];
foreach($array_1 as $element) {
    if(!isset($array_2[$element['grade']]) ||
       $array_2[$element['grade']]['price'] > $element['price']) {
        $array_2[$element['grade']] = $element;
    }
}

We use the grade value as key for our new array - and when no element is set under that key yet, or the one that is set has a price higher than the current element we are looping over, we set that current element under that key.

This results in

Array
(
    [A] => Array
        (
            [model] => iPhone 12
            [grade] => A
            [price] => 95
        )

    [B] => Array
        (
            [model] => iPhone 12
            [grade] => B
            [price] => 85
        )

    [C] => Array
        (
            [model] => iPhone 12
            [grade] => C
            [price] => 75
        )    
)

And now we transform that into your desired format using array_map, wrapped into array_values to reset our keys to a zero-based numerical index:

$array_3 = array_values(array_map(
  function($e) {
    return ['model' => $e['model'], $e['grade'] => $e['price']];
  },
  $array_2)
);

Inside array_map, for each element we return a new array, that has the model value under that same key, and a new element under the key grade, and with the value of the price.

Result:

Array
(
    [0] => Array
        (
            [model] => iPhone 12
            [A] => 95
        )

    [1] => Array
        (
            [model] => iPhone 12
            [B] => 85
        )

    [2] => Array
        (
            [model] => iPhone 12
            [C] => 75
        )
)
CBroe
  • 91,630
  • 14
  • 92
  • 150
0

I recommend implementing the grouping, filtering, and row re-structuring aspects at the same time with a single loop.

Use a "composite key" (meaning a string value that contains multiple values) as a means of identifying duplicates. The composite key will be used as a temporary first level key for simplest comparisons.

If a given row of data is either unique to the result array or has a larger price, simply refuse to process it.

For any rows that qualify for entry into the result array, restructure the row's data and push with the composite key.

When finished iterating, call array_values() to replace the composite keys with indexes.

Code: (Demo)

$result = [];
foreach ($array as $row) {
    $compositeKey = $row['model'] . '_' . $row['grade'];
    if (!isset($result[$compositeKey]) || $result[$compositeKey][$row['grade']] > $row['price']) {
        $result[$compositeKey] = [
            'model' => $row['model'],
            $row['grade'] => $row['price']
        ];
    }
}
var_export(array_values($result));
mickmackusa
  • 43,625
  • 12
  • 83
  • 136