对产品/库存结果集进行分组和计数,形成多维分层数组

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

如何将数据库表的行转换为多维分层结构以计算唯一的库存商品?

我的数据库类似于这样:

CREATE TABLE stock (
    model VARCHAR(100),
    storage VARCHAR(100),
    color VARCHAR(100)
);

INSERT INTO stock VALUES
('iPhone 14 Pro', '128gb', 'Black'),
('iPhone 14 Pro', '256gb', 'Red'),
('iPhone 14 Pro', '128gb', 'Black'),
('iPhone 14 Pro', '256gb', 'Black'),
('iPhone 14 Pro', '256gb', 'Red'),
('iPhone 14 Pro', '128gb', 'White'),
('iPhone 13 Pro', '128gb', 'Black'),
('iPhone 14 Pro', '256gb', 'Red');

所以我的查询结果集如下所示:

[
    ['model' => 'iPhone 14 Pro', 'storage' => '128gb', 'color' => 'Black'],
    ['model' => 'iPhone 14 Pro', 'storage' => '256gb', 'color' => 'Red'],
    ['model' => 'iPhone 14 Pro', 'storage' => '128gb', 'color' => 'Black'],
    ['model' => 'iPhone 14 Pro', 'storage' => '256gb', 'color' => 'Black'],
    ['model' => 'iPhone 14 Pro', 'storage' => '256gb', 'color' => 'Red'],
    ['model' => 'iPhone 14 Pro', 'storage' => '128gb', 'color' => 'White'],
    ['model' => 'iPhone 13 Pro', 'storage' => '128gb', 'color' => 'Black'],
    ['model' => 'iPhone 14 Pro', 'storage' => '256gb', 'color' => 'Red']
]

我想从

model
storage
color
值创建一个父子结构化数组,其中最低级别包含具有特定值组合的项目总数。

[
    'iPhone 14 Pro' => [
        '128gb' => [
            'Black' => 2,
            'White' => 1,
        ],
        '256gb' => [
            'Red' => 3,
            'Black' => 1,
        ],
    ],
    'iPhone 13 Pro' => [
        '128gb' => [
            'Black' => 1,
        ],
    ],
]

我尝试使用一些带有太多

foreach
语句的嵌套循环,但它根本不起作用。 我认为我错误地使用了
array_push()
方法,因为我从未得到正确的结果

php arrays multidimensional-array grouping hierarchical
4个回答
1
投票

假设定义因素,如

model
storage
color
是数据库中的列,您可以创建一个如下所示的简单函数

function generateProductArray($database) {
    $result = array();

    foreach ($database as $entry) {
        $model = $entry['model'];
        $storage = $entry['storage'];
        $color = $entry['color'];

        if (!isset($result[$model])) {
            $result[$model] = array();
        }

        if (!isset($result[$model][$storage])) {
            $result[$model][$storage] = array();
        }

        if (!isset($result[$model][$storage][$color])) {
            $result[$model][$storage][$color] = 0;
        }

        $result[$model][$storage][$color]++;
    }

    return $result;
}

您还可以使用内置 PHP 函数来简化功能/代码,例如

array_reduce( )
:

function generateProductArray($database) {
    return array_reduce($database, function ($result, $entry) {
        [$model, $storage, $color] = array_values($entry);

        $result[$model][$storage][$color] = ($result[$model][$storage][$color] ?? 0) + 1;

        return $result;
    }, []);
}

提供所需的输出。

Array
(
    [iPhone 14 Pro] => Array
        (
            [128gb] => Array
                (
                    [Black] => 2
                )

            [256gb] => Array
                (
                    [Blue] => 1
                    [Red] => 2
                )

        )

)

示例


0
投票

不确定数据的结构,但类似这样的东西可能会起作用:

$data = [
  [
    'model' => 'iPhone 14 Pro',
    'storage' => '128gb',
    'color' => 'Black',
  ],
  [
    'model' => 'iPhone 14 Pro',
    'storage' => '128gb',
    'color' => 'Green',
  ],
  [
    'model' => 'iPhone 14 Pro',
    'storage' => '256gb',
    'color' => 'Blue',
  ],
  [
    'model' => 'iPhone 14 Pro',
    'storage' => '256gb',
    'color' => 'Blue',
  ],
];

$devices = [];
foreach ($data as $phone) {
  list($model, $storage, $color) = array_values($phone);
  $count = $output[$model][$storage][$color] ?? 0;
  $output[$model][$storage][$color] = ++$count;
}

上面将创建一个像这样的数组:

Array
(
    [iPhone 14 Pro] => Array
        (
            [128gb] => Array
                (
                    [Black] => 1
                    [Green] => 1
                )

            [256gb] => Array
                (
                    [Blue] => 2
                )

        )

)

0
投票

以下所有代码片段都提供完全相同的结果数组。

如果您访问数据库只是为了填充此聚合的分层数据结构(您不需要访问原始行逐项行),那么 SQL 完全可以执行计数。

我将演示如何使用

GROUP BY
查询和
COUNT()
来简化结果集、迭代检索到的行、使用
extract()
生成方便的变量,然后进行分层声明。

代码:(PHPize演示

$sql = <<<SQL
SELECT model,
       storage,
       color,
       COUNT(*) count
FROM stock
GROUP BY model,
         storage,
         color
SQL;

$result = [];
foreach ($mysqli->query($sql) as $row) {
    extract($row);
    $result[$model][$storage][$color] = (int) $count;
}
var_export($result);

当然,如果您不喜欢这种风格,您可以在循环体中有效地编写相同的技术。

此方法假设您确切地知道要收集哪些数据列,并且要对父子关系中列的特定顺序进行硬编码。


如果您更喜欢使用非聚合结果集,请迭代检索到的行,使用

extract()
生成方便的变量,然后通过向存储的计数添加 1 来执行计数操作(如果遇到第一个元素,则添加零)时间)。

代码:(PHPize演示

$result = [];
foreach ($mysqli->query("SELECT * FROM stock") as $row) {
    extract($row);
    $result[$model][$storage][$color] = ($result[$model][$storage][$color] ?? 0) + 1;
}
var_export($result);

如果您更喜欢函数式代码样式,请使用

array_reduce()
,但您需要显式获取结果集。与经典的
foreach()
循环相比,它太冗长了,不符合我的口味。

代码:(PHPize演示

var_export(
    array_reduce(
        $mysqli->query("SELECT * FROM stock")->fetch_all(MYSQLI_ASSOC),
        function($result, $row) {
            extract($row);
            $result[$model][$storage][$color] = ($result[$model][$storage][$color] ?? 0) + 1;
            return $result;
        }
    )
);

最后,如果您想享受完全动态的片段并依赖结果集中的列顺序来指示层次结构的级别,您可以在嵌套循环中使用引用变量。

代码:(PHPize演示

$result = [];
foreach ($mysqli->query("SELECT model, storage, color FROM stock") as $row) {
    $ref = &$result;
    foreach ($row as $value) {
        $ref = &$ref[$value];
    }
    $ref = ($ref ?? 0) + 1;
}
var_export($result);

本答案中找到的所有技术也可以通过询问您最喜欢的代码生成人工智能工具来获得。然而,我发现当我检查 ChatGPT 时,它在每个级别上编写了不必要的

isset()
检查,如 @Darren 的答案所示。它还错误地实现了基于参考的技术。在没有尝试编码的情况下在 Stack Overflow 上提问之前,请花 120 秒向您最喜欢的 AI 工具寻求帮助。


-1
投票

可以使用嵌套循环来创建多维数组来表示属性的不同组合。

$models = ['iPhone 14 Pro'];
$storages = ['128gb', '256gb'];
$colors = ['Black', 'Blue'];

$result = [];

foreach ($models as $model) {
    foreach ($storages as $storage) {
        foreach ($colors as $color) {
            $result[] = [
                'model' => $model,
                'storage' => $storage,
                'color' => $color
            ];
        }
    }
}

// 现在 $result 包含模型、存储和颜色的所有组合

print_r($result);

你的结果将如下所示

Array
(
    [0] => Array
        (
            [model] => iPhone 14 Pro
            [storage] => 128gb
            [color] => Black
        )

    [1] => Array
        (
            [model] => iPhone 14 Pro
            [storage] => 128gb
            [color] => Blue
        )

    [2] => Array
        (
            [model] => iPhone 14 Pro
            [storage] => 256gb
            [color] => Black
        )

    [3] => Array
        (
            [model] => iPhone 14 Pro
            [storage] => 256gb
            [color] => Blue
        )
)
© www.soinside.com 2019 - 2024. All rights reserved.