如何对关联数组的数组进行分组并声明自定义键?

时间:2018-08-10 20:31:08

标签: php arrays multidimensional-array merge grouping

有人可以帮我转换成分组格式的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"
        )
    );

我做了一些尝试,但是似乎找不到如何使它工作的方法。

4 个答案:

答案 0 :(得分:2)

您只需要迭代数据行,确定每行是否是第一个出现的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',
  ),
)

答案 1 :(得分:0)

我不确定此结构是否理想-看来您的键"Score1""Score2"等最好是像scores => [1050, 1130, ...]这样的数组,并且感觉像{{ 1}}应该是结果数组中的键。但是无论如何,这都会提供您要求的输出:

id

输出

$res = [];

foreach ($arr as $e) {
    if (!array_key_exists($e['id'], $res)) {
        $res[$e['id']] = [];
    }

    $res[$e['id']]["Score".(count($res[$e['id']])+1)] = $e['sat_total'];
}

$count = 0;

foreach ($res as $k => $v) {
    $res[$k]['id'] = $k;
    $res[$count++] = $res[$k];
    unset($res[$k]);
}

print_r($res);

请注意,我进行了两次遍历,这有点​​冗长,但是花一些时间在第一次遍历中将数据id键入数组时,应该会改善对每个元素到 O(1 )哈希,因此我认为值得使用额外的循环块。

这里是repl

答案 2 :(得分:0)

此方法将查找与$ id匹配的分数。
它使用三个array_intersects来匹配所有正确的值。
在您的情况下,此方法将仅循环唯一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

答案 3 :(得分:0)

$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

它通过期待匹配id来工作。此解决方案假定您的原始数组按id排序!因此,除非您信任输入,否则请不要使用此解决方案!

否则,这是一种简单,快速且易读的解决方案,对我来说看起来像是学校的练习?

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