基于两列将数据分组到多维数组中,如果有多个值,则在给定组中创建子数组

问题描述 投票:0回答:4

我有一个关联数组的索引数组,如下所示:

[
    ['brand' => 'ABC', 'model' => 'xyz', 'size' => 13],
    ['brand' => 'QWE', 'model' => 'poi', 'size' => 23],
    ['brand' => 'ABC', 'model' => 'xyz', 'size' => 18]
];

我需要减少/合并/重组数据以基于

brand
model
进行分组。如果在对这两列进行分组时,
brand
model
组合出现多次,则
size
值应形成索引子数组。否则,
size
值可以保留为单个字符串值。

我想要的结果:

[
    ['brand' => 'ABC', 'model' => 'xyz', 'size' => [13, 18]],
    ['brand' => 'QWE', 'model' => 'poi', 'size' => 23],
];
php arrays multidimensional-array grouping array-merge
4个回答
3
投票

就算法而言,你只需要:

  1. 创建一个空数组。

  2. 扫描源数组中的每个数组元素,为遇到的每个新品牌/型号创建一个新元素(在空数组中),并添加尺寸子数组。

  3. 如果已经有品牌/型号条目,只需将尺寸添加到子数组中(如果尚不存在)。

您可以按如下方式实现(粗略,但它有效):

<?php
    // Test data.
    $sourceArray = array(array('brand'=>'ABC', 'model'=>'xyz', 'size'=>13),
                         array('brand'=>'QWE', 'model'=>'poi', 'size'=>23),
                         array('brand'=>'ABC', 'model'=>'xyz', 'size'=>18),
                        );
    $newArray = array();

    // Create a new array from the source array. 
    // We'll use the brand/model as a lookup.
    foreach($sourceArray as $element) {

        $elementKey = $element['brand'] . '_' . $element['model'];

        // Does this brand/model combo already exist?
        if(!isset($newArray[$elementKey])) {
            // No - create the new element.
            $newArray[$elementKey] = array('brand'=>$element['brand'],
                                           'model'=>$element['model'], 
                                           'size'=>array($element['size']),
                                           );
        }
        else {
            // Yes - add the size (if it's not already present).
            if(!in_array($element['size'], $newArray[$elementKey]['size'])) {
                $newArray[$elementKey]['size'][] = $element['size'];
            }
        }
    }

    // *** DEBUG ***
    print_r($newArray);
?>

顺便说一下,为了方便访问,我将 size 子数组设置为始终是一个数组。 (即:您不必允许它可能只是一个元素。)


0
投票
//$array is the array in your first example.

foreach($array as $item) {
  $itemname = $item["brand"] . "_" . $item["model"]

  $new_array[$itemname]["brand"]  = $item["brand"];
  $new_array[$itemname]["model"]  = $item["model"];
  $new_array[$itemname]["size"][] = $item["size"];
}

0
投票

“升级”到 knarf 的片段....

foreach($array as $item) {
  $itemname = $item["brand"] . "_" . $item["model"]

  $new_array[$itemname]["brand"]  = $item["brand"];
  $new_array[$itemname]["model"]  = $item["model"];
  $new_array[$itemname]["size"][ $item["size"] ] = 1;
}

foreach($new_array as $itemname=>$data) {
  if(isset($data['size']) && is_array($data['size'])) {
    $new_array[$itemname]['size']=array_keys($new_array[$itemname]['size']);
  }
}

不再有重复...


0
投票

我将从字面上解释这个问题并提供准确描述的输出结构。

临时复合键允许非常快速地查找以前遇到的

brand
-
model
对。重要的是,使用分隔字符(不在两个值中使用)来分隔复合字符串中的每个值,这样就不会出现意外的“数据冲突”。

如果给定的“品牌-型号”组合仅出现一次,则原始行结构将被推入结果数组中。否则,“大小”数据将转换为索引数组,并将后续唯一大小值推入子数组中。

经典

foreach()
:(演示)(使用array_unique删除潜在重复大小

$result = [];
foreach ($array as $row) {
    $compositeKey = $row['brand'] . '_' . $row['model'];
    if (!isset($result[$compositeKey])) {
        $result[$compositeKey] = $row;
    } else {
        $result[$compositeKey]['size'] = array_merge(
            (array)$result[$compositeKey]['size'],
            [$row['size']]
        );
    }
}
var_export($result);

使用

array_reduce()
进行函数式编程:(演示

var_export(
    array_values(
        array_reduce(
            $array,
            function ($carry, $row) {
                $compositeKey = $row['brand'] . '_' . $row['model'];
                if (!isset($carry[$compositeKey])) {
                    $carry[$compositeKey] = $row;
                } else {
                    $carry[$compositeKey]['size'] = array_merge(
                        (array)$carry[$compositeKey]['size'],
                        [$row['size']]
                    );
                }
                return $carry;
            }
        )
    )
);

如果我说实话,我会为我的输出创建一个一致的数据结构,并且大小始终是一个子数组。以下是如何修改上面的代码片段,以在第一次遇到时将 size 元素转换为数组,并将所有随后遇到的 size 值推送到该组的子数组中:(Demo)

$result = [];
foreach ($array as $row) {
    $compositeKey = $row['brand'] . '_' . $row['model'];
    if (!isset($result[$compositeKey])) {
        $row['size'] = (array)$row['size'];
        $result[$compositeKey] = $row;
    } else {
        $result[$compositeKey]['size'][] = $row['size'];
    }
}
var_export(array_values($result));
© www.soinside.com 2019 - 2024. All rights reserved.