按一列对二维数组数据进行分组,使用默认值填充子数组,使用映射数组对另一列的值求和

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

我正在尝试对二维数组中的数据进行分组,同时利用查找数组来确保每个组中都存在默认值。

我的查找/映射数组将语言 ID 与语言名称相关联。

$langs = [
    5 => "english",
    10 => "french",
    12 => "german"
    ...
];

另一个数组保存应按日期值分组的数据。

$posts = [
    [
        "date" => "13-07-2022",
        "lang_id" => 5,
        "amount" => 90,
    ],
    [
        "date" => "13-07-2022",
        "lang_id" => 10,
        "amount" => 34,
    ],
    [
        "date" => "14-07-2022",
        "lang_id" => 5,
        "amount" => 7,
    ],
    ...
];

$posts
每天都有该语言的帖子。当没有任何帖子时,数组中不会有任何条目。

我想重构数据以按日期分组,每个子数组应包含日期和累积的关联语言量:

$result = [
    [
        "date" => "13-07-2022",
        "english" => 90,
        "french" => 34,
        "german" => 0
    ],
    [
        "date" => "14-07-2022",
        "english" => 6,
        "french" => 0,
        "german" => 0
    ],
    ...
];

这是,当“主”语言列表中没有帖子时,我会将该语言设置为 0。

我尝试迭代

$posts
及其中的
langs
数组,以便用零填充每个新处理的项目,但我未能实现它。 我尝试的是:

$d = $post[0]['date'];
$result = [];

foreach ($posts as $post) {
    if ($d != $post['date']) {
        $d = $post['date'];
        $result[] = $proc;
        $proc = [];
        $proc['date'] = $d;
    }

    foreach ($langs as $id => $name) {
        if ($id == $post['lang_id']) {
            $proc[$name] = $post['amount'];
        } elseif (!isset($proc[$name])) {
            $proc[$name] = 0;
        }
    }
}

$result[] = $proc;

我的观点是是否有更好的方法来实现这一目标,无需嵌套循环或更有效的方法

php arrays sum mapping grouping
3个回答
1
投票

如果循环遍历 posts 数组并针对每个项目,首先检查是否已经有该日期的结果。如果没有 - 它会使用

array_fill_keys()
添加 langs 中的值,值为 0,然后添加日期(您可以先使用
array_merge()
创建日期)。

然后它总是添加各种键...

$结果=[];

foreach ($posts as $post) {
    if (array_key_exists($post['date'], $results) == false) {
        $results[$post['date']] = array_fill_keys($langs, 0);
        $results[$post['date']]['date'] = $post['date'];
    }
    $results[$post['date']][$langs[$post['lang_id']]] = $post['amount'];
}

var_dump(array_values($results));

这给出了...

array(2) {
  [0] =>
  array(4) {
    'english' =>
    int(90)
    'french' =>
    int(34)
    'german' =>
    int(0)
    'date' =>
    string(10) "13-07-2022"
  }
  [1] =>
  array(4) {
    'english' =>
    int(7)
    'french' =>
    int(0)
    'german' =>
    int(0)
    'date' =>
    string(10) "14-07-2022"
  }
}

把日期放在第一位...

$results[$post['date']] = array_merge(['date' => $post['date']], array_fill_keys($langs, 0));

0
投票
$langs = [
  5  => 'english',
  10 => 'french',
  12 => 'german',
];

$posts = [
  [ 'date' => '13-07-2022', 'lang_id' => 5, 'amount' => 90, ],
  [ 'date' => '13-07-2022', 'lang_id' => 10, 'amount' => 34, ],
  [ 'date' => '14-07-2022', 'lang_id' => 5, 'amount' => 7, ],
];

$langs_template = array_combine($langs, array_fill(0, count($langs), 0));

$result =
  array_values(
    array_reduce(
      $posts,
      function ($carry, $item) use ($langs, $langs_template) {
        $date = $item['date'];
        if (!array_key_exists($date, $carry)) {
          $carry[$date] = [ 'date' => $date, ...$langs_template ];
        }
        $carry[$date][$langs[$item['lang_id']]] = $item['amount'];
        return $carry;
      },
      []
    )
  );

print_r($result);

输出:

Array
(
    [0] => Array
        (
            [date] => 13-07-2022
            [english] => 90
            [french] => 34
            [german] => 0
        )

    [1] => Array
        (
            [date] => 14-07-2022
            [english] => 7
            [french] => 0
            [german] => 0
        )

)

0
投票
  1. 在循环之前声明要用于每个日期组的默认值数组
  2. 循环 posts 数组
  3. 使用
    extract()
    为每次迭代生成方便的临时变量
  4. 如果遇到的日期是新的,请设置默认值
  5. 利用查找数组将当前金额添加到正确的语言列

代码:(演示

$defaults = array_fill_keys($langs, 0);
$result = [];
foreach ($posts as $row) {
    extract($row);
    $result[$date] ??= ['date' => $date] + $defaults;
    $result[$date][$langs[$lang_id]] += $amount;
}
var_export(array_values($result));

为了避免在循环后重新索引结果,请将引用推入结果中。 演示

$defaults = array_fill_keys($langs, 0);
$result = [];
foreach ($posts as $row) {
    extract($row);
    if (!isset($ref[$date])) {
        $ref[$date] = ['date' => $date] + $defaults;
        $result[] = &$ref[$date];
    }
    $ref[$date][$langs[$lang_id]] += $amount;
}
var_export($result);
© www.soinside.com 2019 - 2024. All rights reserved.