基于单个列将2d阵列中的行数据分组,并将唯一数据推送到相应的子阵列中


Group row data within a 2d array based on a single column and push unique data into respective subarrays

我需要在一个多维数组中对数据进行分组,该数组可以在单列entry_id上关联。

除了entry_id之外,在其他相关行(icnameresidency)中也存在相同的其他列。分组时,可以简单地覆盖这些数据点——换句话说,我不需要在相应的组中收集相同值的多个副本。

最后,各个组中会有不同的数据点——这些值需要作为子数组存储在组中,这样就不会丢失数据。

如果一个组中只有一行的数据,则不需要将file_nodetail数据转换为数组。这意味着结果数组将具有可变的深度——一些行将是平面的,而另一些行可能是二维的。

样本输入:

$array = [
    [
        'entry_id' => 1,
        'ic' => 2147483647,
        'name' => 'Kořínková Blanka',
        'residency' => 'Štětí, Lukešova 354, 411 08',
        'file_no' => 'KSUL 77 INS 18898 / 2013',
        'detail' => '749371da-725c-4738-8def-2f7167142a6f'
    ],
    [
        'entry_id' => 1,
        'ic' => 2147483647,
        'name' => 'Kořínková Blanka',
        'residency' => 'Štětí, Lukešova 354, 411 08',
        'file_no' => 'KSUL 77 INS 21218 / 2013',
        'detail' => '43b6a718-4647-451d-9c53-50dfee8403ff'
    ],
    [
        'entry_id' => 2,
        'ic' => 46900217,
        'name' => 'ENTEC a.s. "v likvidaci"',
        'residency' => 'Staré Město, Brněnská 1916, 686 03',
        'file_no' => 'KSBR 28 INS 1232 / 2013',
        'detail' => 'e2155a52-c464-4357-b71b-4f4ff75585eb'
    ],
];

所需输出(基于相同的"entry_id"分组):

Array
(
    [0] => Array
        (
            [entry_id] => 1
            [ic] => 2147483647
            [name] => Kořínková Blanka
            [residency] => Štětí, Lukešova 354, 411 08
            [file_no] => Array
                 (
                       [0] => KSUL 77 INS 18898 / 2013
                       [1] => KSUL 77 INS 21218 / 2013
                 )
            [detail] => Array
                 (
                       [0] => A749371da-725c-4738-8def-2f7167142a6f
                       [1] => 43b6a718-4647-451d-9c53-50dfee8403ff
                 )
        )
    [1] => Array
        (
            [entry_id] => 2
            [ic] => 46900217
            [name] => ENTEC a.s. "v likvidaci"
            [residency] => Staré Město, Brněnská 1916, 686 03
            [file_no] => KSBR 28 INS 1232 / 2013
            [detail] => e2155a52-c464-4357-b71b-4f4ff75585eb
        )
)

您的问题可以通过一个功能块来解决,使用array_reduce()array_merge()原则:

$mergeId = 'entry_id';
$data = array_reduce($data, function($c, $x) use ($mergeId)
{
   $c[$x[$mergeId]] = isset($c[$x[$mergeId]])
      ?array_combine(
          $z=array_keys($c[$x[$mergeId]]), 
          array_map(function($y) use ($x, $c, $mergeId)
          {
             return in_array($x[$y], (array)$c[$x[$mergeId]][$y])
                ?$c[$x[$mergeId]][$y]
                :array_merge((array)$c[$x[$mergeId]][$y], [$x[$y]]);
          }, $z)
       )
      :$x;
   return $c;
}, []);

如果需要重新索引结果集,则可能需要应用array_values()(因此键将是连续的,从0开始)。检查小提琴。

使用嵌套循环迭代单个数组以获得潜在匹配是一种间接的"暴力";技术——在一些边缘情况下,这是可以容忍的,但在这种情况下,更具性能和专业性的方法是在迭代每一行时分配临时的一级键。由于PHP处理数组/键的方式,新的关联数组允许简单/快速的搜索。

当第一次遇到entry_id值时,只需保存整行即可。当第一次之后遇到entry_id值时,需要将标量类型的file_nodetail元素转换为数组类型。这可以手动完成,但array_merge_recursive()提供了这种"手动";魔术;天生的。

如果不想保留第一级分组密钥,请在迭代完成后调用array_values()

代码:(演示)

$result = [];
foreach ($array as $row) {
    if (!isset($result[$row['entry_id']])) {
        $result[$row['entry_id']] = $row;
    } else {
        $result[$row['entry_id']] = array_merge_recursive(
            $result[$row['entry_id']],
            ['file_no' => $row['file_no'], 'detail' => $row['detail']]
        );
    }
}
var_export(array_values($result));

组内手动重新铸造元素(演示)

$result = [];
foreach ($array as $row) {
    if (!isset($result[$row['entry_id']])) {
        $result[$row['entry_id']] = $row;
    } else {
        $result[$row['entry_id']]['file_no'] = (array) $result[$row['entry_id']]['file_no'];  // re-cast as single-element array
        $result[$row['entry_id']]['detail'] = (array) $result[$row['entry_id']]['detail'];  // re-cast as single-element array
        $result[$row['entry_id']]['file_no'][] = $row['file_no']; // push new element into subarray
        $result[$row['entry_id']]['detail'][] = $row['detail']; // push new element into subarray
    }
}
var_export(array_values($result));