【问题标题】:How to group an array of associative arrays and declare custom keys?如何对一组关联数组进行分组并声明自定义键?
【发布时间】:2019-01-18 11:51:13
【问题描述】:

有人可以帮助我将 php 数组转换为分组格式吗?我正在尝试按id 对它们进行分组。我想转换以下数组:

$Arr1=Array
    (
        0 => Array
        (
            "id" => "4123",
            "test_number" => "1",
            "sat_total" => "1050"
        ),
        1 => Array
        (
            "id" => "4123",
            "test_number" => "2",
            "sat_total" => "1130"
        ),
        2 => Array
        (
            "id" => "4123",
            "test_number" => "3",
            "sat_total" => "1120"
        ),
        3 => Array
        (
            "id" => "5555",
            "test_number" => "1",
            "sat_total" => "1130"
        ),
        4 => Array
        (
            "id" => "5555",
            "test_number" => "2",
            "sat_total" => "1160"
        )
    );

进入这个:

$Arr2=Array
    (
        0 => Array
        (
            "id" => "4123",
            "Score1" => "1050",
            "Score2" => "1130",
            "Score3" => "1120"
        ),
        1 => Array
        (
            "id" => "5555",
            "Score1" => "1130",
            "Score2" => "1160"
        )
    );

我已经尝试了一点,但似乎找不到如何让它发挥作用。

【问题讨论】:

  • 看起来并不复杂。到目前为止你有什么?

标签: php arrays multidimensional-array merge grouping


【解决方案1】:

此方法将查找与 $id 匹配的分数。
它使用三个 array_intersect 来匹配所有正确的值。
此方法只会循环唯一 ID 的数量,在您的情况下会循环两次。
加上创建乐谱键的时间。

我同意 ggorlen 关于钥匙的说法。这也将创建更高效​​的代码。

$ids = array_column($Arr1, "id");
$sat = array_column($Arr1, "sat_total");

foreach(array_unique($ids) as $id){
    $new[$id] = ["id" => $id];
    $tmp = array_values(array_intersect_key($sat,array_intersect_key($Arr1, array_intersect($ids, [$id]))));
    for($i=1;$i<=count($tmp);$i++) $new[$id]["Score" . $i] = $tmp[$i-1];
}
var_dump($new);

https://3v4l.org/ag3To

输出是一个以 id 为键的关联数组。
如果你想让它被索引,你可以使用 array_values。


只是为了展示使用一个分数数组的代码可以提高多少效率。
这就是它的样子:

$ids = array_column($Arr1, "id");
$sat = array_column($Arr1, "sat_total");

foreach(array_unique($ids) as $id){
    $new[] = ["id" => $id, "scores" => array_values(array_intersect_key($sat,array_intersect_key($Arr1, array_intersect($ids, [$id]))))];
}
var_dump($new);

https://3v4l.org/mdA0W

【讨论】:

  • array_valuesarray_intersect_key 效率不高。这些都是在每次迭代时遍历整个输入数组,所以如果我没记错的话,这看起来像 O(n^2)
  • 看你想如何高效阅读。转换数组的三行代码在代码方面是有效的。时间效率是另一回事。但在我看来,这并没有那么糟糕。你的代码更快,但没那么快3v4l.org/NJoQk
  • 感谢您的基准测试,但请在更大的测试用例上尝试一下——74 太小,无法证明 O(n) 和 O(n^2) 之间的差异很大。试试这个来随机生成 >1000 个测试用例:repl.it/repls/FractalColorlessStructure。这是仅 5000 个项目的差异:0.6497859954834 与 3812.0427131653。这是一个显着的差异,对于更大的数据集,情况会变得更糟。
  • 但是您实际上是在创建一组唯一 ID。显然,这不适用于应该对项目进行分组和循环唯一 ID 的代码。
  • 尊敬的,我不得不同意,这是过度设计的,可以用更简单、更容易阅读的 sn-p 来处理。我添加了我的解决方案以供比较。
【解决方案2】:
$arr2 = [];
$i = 0;
$length = count($arr1);
do {
    $builder = $arr1[$i];
    // grab the first item from the original array

    $builder = [
        // set its initial properties
        'id' => $arr1[$i]['id'],
        'Score1' => $arr1[$i]['sat_total'],
    ];

    // initialise the subsequent score number
    $testNumber = 2;

    // prepare to look ahead in the original array for a matching id
    while (($i + 1) < $length) { // only look ahead if it is possible to
        if ($arr1[$i + 1]['id'] == $builder['id']) {
            // did you find a matching id? if so, let's set the subsequent score
            $builder["Score$testNumber"] = $arr1[$i + 1]['sat_total'];
            $testNumber++; // increase the next score number
            $i++; // increase the original array index
        } else {
            // no luck? let's go forwards and set the next record
            break;
        }
    }
    $arr2[] = $builder; // set the built record into the new array
    $i++; // move the pointer forwards
} while ($i < $length); // as long as there are items ahead

你不经常使用do-while。但它有效:)

输入你的原始数组$arr1$arr2 将被设置。

它的工作原理是期待匹配ids。此解决方案假定您的原始数组按id 排序!因此,除非您相信输入 - 不要使用此解决方案!

否则,这是一个简单、快速且可读性强的解决方案,在我看来像是学校练习?

如果您想要安全的东西,这里的其他解决方案都是合适的。

【讨论】:

    【解决方案3】:

    您只需要迭代您的数据行,确定每一行是否是第一个出现的id 值,然后声明初始值,或者向组中添加一个可变键元素。循环结束后,调用array_values() 重新索引数组(删除临时键)。

    代码:(Demo)

    $Arr1=[
        ["id" => "4123", "test_number" => "1", "sat_total" => "1050"],
        ["id" => "4123", "test_number" => "2", "sat_total" => "1130"],
        ["id" => "4123", "test_number" => "3", "sat_total" => "1120"],
        ["id" => "5555", "test_number" => "1", "sat_total" => "1130"],
        ["id" => "5555", "test_number" => "2", "sat_total" => "1160"]
    ];
    
    foreach ($Arr1 as $set) {
        if (!isset($result[$set['id']])) {
            $result[$set['id']] = ['id' => $set['id'], 'Score1' => $set['sat_total']];
        } else {
            $result[$set['id']]['Score' . sizeof($result[$set['id']])] = $set['sat_total'];
        }
    }
    
    var_export(array_values($result));
    

    输出:

    array (
      0 => 
      array (
        'id' => '4123',
        'Score1' => '1050',
        'Score2' => '1130',
        'Score3' => '1120',
      ),
      1 => 
      array (
        'id' => '5555',
        'Score1' => '1130',
        'Score2' => '1160',
      ),
    )
    

    【讨论】:

      猜你喜欢
      • 2021-03-05
      • 1970-01-01
      • 1970-01-01
      • 2020-06-03
      • 2015-09-23
      • 1970-01-01
      • 2022-01-08
      相关资源
      最近更新 更多