实施数组长度相等

时间:2016-08-11 13:19:29

标签: php arrays

TL; DR

给定一个数组数组,我需要确保每个数组的长度都与第一个数组相同。

原始问题

我有一个应该将矩阵线转换为列的函数。

 Original     Result
  1,2,3       1,4,7
  4,5,6       2,5,8
  7,8,9       3,6,9

当前的实施方式

我使用array_map实现了它:

<?php
$items = array_map(function (...$items) {
    return $items;
}, ...$values);

我需要实现的目标

当数组比第一个数组短时我需要抛出LengthException

理想的解决方案

理想的解决方案是将第一个元素的长度存储在array_map之外,并将其与array_map迭代的当前项的长度进行比较,如下所示:

<?php
$expectedLength = count(reset($values));
$items = array_map(function (...$items) {
    $length = count($items);
    if ($length !== $expectedLength) {
        throw new LengthException("Element size differs ({$length} should be {$expectedLength})");
    }
    return $items;
}, ...$values);

为什么理想的解决方案不起作用

从PHP手册:

  

通常在使用两个或多个数组时,它们的长度应相等,因为回调函数与相应的元素并行应用。如果数组的长度不等,则较短的数组将使用空元素进行扩展,以匹配最长的数组。

可悲的是,较短的数组将填充空元素。

由于原始数组可能有空元素,因此我没有其他方法可以测试数组最初是否比第一个短。

我的第一个麻烦的解决方案

我必须在array_map之前对其进行测试,并且我不相信这是一个很好的解决方案:

<?php
$expectedLength = count(reset($values));
$diffLength = count(array_intersect_key(...$values));

if ($diffLength !== $expectedLength) {
    throw new LengthException("Element size differs ({$diffLength} should be {$expectedLength})");
}

$items = array_map(function (...$items) {
    return $items;
}, ...$values);

你能帮我找到更好的方法吗?我想在迭代中做到这一点,但如果你找到一种更好的方法来查找迭代前我们是否有一个不同长度的元素(我不想使用array_intersect_key),那么& #39;也好。

2 个答案:

答案 0 :(得分:0)

您可以通过小幅调整来保持理想的解决方案:

array_map(function (...$items) {
    $nonNullItems = array_filter(
        $items,
        function ($item) { return $item !== null }
    );
    $length = count($nonNullItems);
    if ($length !== $expectedLength) {
        throw new LengthException(
            "Element size differs ({$length} should be {$expectedLength})"
        );
    }
    return $items;
}

请注意这个补充:

array_filter($items, function ($item) { return $item !== null});

它将过滤掉null(但不是0或.0)的项目中的所有元素。

编辑:我不确定,但array_filter($items)也可以正常工作,但我不确定如果没有回调空或空项目被解雇,所以上面确保只有null是驳回。

答案 1 :(得分:0)

代码:(Demo

$arrays=[
    [['a','b','c'],['d','e','f'],['g','h','i']],   // test array #1: no missing elements
    [['a','b','c'],['d','e','f'],['g','h']],       // test array #2: missing element i
    [['a','b','c'],['d','e'],['g','h','i']],       // test array #3: missing element f
    [['a','b'],['d','e','f'],['g','h','i']],       // test array #4: missing element c
    [['a','b','c'],['d','e','f'],['g','h',NULL]],  // test array #5: NULL on i
];

// find non-specific imbalance using COUNT_RECURSIVE
foreach($arrays as $i=>$a){  // running 5 separate tests
    echo "Test #$i:\n";
    if(($originalsize=sizeof($a,1))===($rotatedsize=sizeof(array_map(function(){return func_get_args();},...$a),1))){
        echo "@$i originalsize ($originalsize) = rotatedsize ($rotatedsize)\n";
    }else{
        echo "@$i originalsize ($originalsize) DOES NOT EQUAL rotatedsize ($rotatedsize)\n";
    }
}

echo "\n\n---\n\n";

// Find specific subarray imbalances using COUNT
foreach($arrays as $i1=>$a){  // running 5 separate tests
    echo "Test #$i1:\n";
    $firstsize=sizeof($a[0]);
    foreach(array_slice($a,1,null,true) as $i2=>$others){
        if($firstsize==($othersize=sizeof($others))){
            echo "The first size ($firstsize) = subarray $i2 size ($othersize)\n";
        }else{
            echo "The first size ($firstsize) DOES NOT EQUAL subarray $i2 size ($othersize)\n";
        }
    }
    echo "\n";
}

输出:

Test #0:
@0 originalsize (12) = rotatedsize (12)
Test #1:
@1 originalsize (11) DOES NOT EQUAL rotatedsize (12)
Test #2:
@2 originalsize (11) DOES NOT EQUAL rotatedsize (12)
Test #3:
@3 originalsize (11) DOES NOT EQUAL rotatedsize (12)
Test #4:
@4 originalsize (12) = rotatedsize (12)


---

Test #0:
The first size (3) = subarray 1 size (3)
The first size (3) = subarray 2 size (3)

Test #1:
The first size (3) = subarray 1 size (3)
The first size (3) DOES NOT EQUAL subarray 2 size (2)

Test #2:
The first size (3) DOES NOT EQUAL subarray 1 size (2)
The first size (3) = subarray 2 size (3)

Test #3:
The first size (2) DOES NOT EQUAL subarray 1 size (3)
The first size (2) DOES NOT EQUAL subarray 2 size (3)

Test #4:
The first size (3) = subarray 1 size (3)
The first size (3) = subarray 2 size (3)