如何通过小于值从数组中获取子数组键

时间:2017-08-01 19:13:56

标签: php array-map array-filter

我希望从数组中获取小于数值的子数组键 这是一个例子:

$arr_less_than = array(55,60,10,70);

$BlackList = array(10,8,15,20);

$MasterArray = array(
    10 => array(1 => array(50,20,5,40), 2 => array(70,77,58,10), 3 => array(155,95,110,105), 4 => array(250,215,248,188)),
    11 => array(1 => array(5,65,49,100), 2 => array(80,85,60,30), 3 => array(175,85,95,120), 4 => array(235,205,218,284)),
    12 => array(1 => array(82,80,55,80), 2 => array(90,90,74,110), 3 => array(180,122,156,222), 4 => array(255,225,233,263)),
    13 => array(1 => array(350,360,400,375), 2 => array(95,99,111,75), 3 => array(188,112,66,111), 4 => array(66,69,33,110)),
);

现在,如果子数组键不在数组$MasterArray中,我需要从$arr_less_than获得小于$BlackList的子数组键。

对于上面的示例,结果必须返回array(12,13)

注意:我不想使用foreach循环

1 个答案:

答案 0 :(得分:0)

这里有两个解决方案 - 一个用于所有子阵列符合标准,一个用于任何子阵列符合标准(这似乎是OP所考虑的)。最后,基于foreach的解决方案适用于后一种情况,其中任何子阵列都符合标准。

如果我正确理解问题,目标是识别MasterArray中的行,其中所有子数组的值都大于$arr_less_than中的对应值。

OP不想使用foreach(请参阅基于foreach的答案的答案,这些答案更简单) - 这实际上可能会产生更高效的版本,因为它可以避免不必要的比较并保存一些周期,所以这里是一个使用数组函数的注释严重的版本。

我已经排除了可以从OP的帖子中复制的数据:

function getMatchingRows($arr_less_than, $MasterArray, $BlackList)
{
    return  array_values(  // When we're done we just want a straight array of the keys from $MasterArray
        array_filter(
            array_keys($MasterArray), // Iterate over $MasterArray's keys (Because we need the keys for the BlackList)
            function ($v) use ($BlackList, $MasterArray, $arr_less_than) {
                // Filter out MasterArray Entries that dont meet the criteria
                echo "Evaluate $MasterArray[$v]" . PHP_EOL;
                // Remove array entries whose key is in the BlackList
                if (in_array($v, $BlackList)) {
                    echo "\tBlacklisted" . PHP_EOL;
                    return false;
                }
                // For each entry in the MasterArray value, add up the number of non-matching entries
                $y = array_reduce(
                    $MasterArray[$v],
                    function ($c1, $sub) use ($arr_less_than) {
                        // For each subarray entry in a MasterArray value, reduce the array to a count
                        // of elements whose value is less than the corresponding value in the $arr_less_than
                        $s1 = array_reduce(
                            array_keys($sub),
                            function ($carry, $key) use ($sub, $arr_less_than) {
                                if ($sub[$key] <= $arr_less_than[$key]) {
                                    return ++$carry;
                                }
                            },
                            0 // Initial value for the array_reduce method
                        );
                        // $s1 will be a count of non-matching values
                        return $c1 + $s1;
                    },
                    0 //Initial value for the array_reduce method
                );
                echo "\t$y" . PHP_EOL;
                // Include the array value in the filter only if there are no non-matching values ($y == 0)
                return !$y;
            }
        )
    );
}
print_r(getMatchingRows($arr_less_than, $MasterArray, $BlackList));

基本思想是从最外层的数组生成一个键列表 - 所以我们用array_filter迭代它们。然后我们在黑名单中排除那些带有密钥的那些。不在黑名单中的行通过迭代每个sub =数组值并将它们与$ arr_less_than进行正位数比较并将每个值加1而不是大于$ arr_less_than中的相应成员来减少为整数。然后将这些值汇总为MasterArray行中的所有成员。如果结果为零,则该行通过。最后,最终结果传递给array_values以规范化生成的数组。

请注意,这要求比较所有值,即使第一个子数组中的第一个子值失败也是如此。因此,可以逃避的foreach方法可能更有效。

这基本上是相同的方法,没有评论和几个快捷方式:

function getMatchingRows($arr_less_than, $MasterArray, $BlackList)
{
    return  array_values(  // When we're done we just want a straight array of the keys from $MasterArray
        array_filter(
            array_keys($MasterArray),
            function ($v) use ($BlackList, $MasterArray, $arr_less_than) {
                return !in_array($v, $BlackList) && !array_reduce(
                    $MasterArray[$v],
                    function ($c1, $sub) use ($arr_less_than) {
                        return $c1  ?: array_reduce(
                            array_keys($sub),
                            function ($carry, $key) use ($sub, $arr_less_than) {
                                return $carry ?: ($sub[$key] <= $arr_less_than[$key] ? 1 : 0);
                            },
                            0
                        );
                    },
                    0
                );
            }
        )
    );
}

array_reduce中的一些方法使用?:运算符进行短路,因为实际计数是无关紧要的。一旦计数超过零,该行就会失败,无论如何。

如果标准是至少一个子阵列的所有成员都大于参考数组,则这是类似的代码。

function getMatchingRowsAny($arr_less_than, $MasterArray, $BlackList)
{
    return  array_values(  // When we're done we just want a straight array of the keys from $MasterArray
        array_filter(
            array_keys($MasterArray), // Iterate over $MastrArray's keys (Because we need the keys for theBlackList)
            function ($v) use ($BlackList, $MasterArray, $arr_less_than) {
                // Filter out MasterArray Entries that dont meet the criteria
                echo "Evaluate \MasterArray[$v]" . PHP_EOL;
                // Remove array entries whose key is in the BlackList
                if (in_array($v, $BlackList)) {
                    echo "\tBlacklisted" . PHP_EOL;
                    return false;
                }
                // For each entry in the MasterArray value, add up the number of non-matching entries
                $y = array_reduce(
                    $MasterArray[$v],
                    function ($c1, $sub) use ($arr_less_than) {
                        // For each subarray entry in a MasterArray value, reduce the array to a flag
                        // indicating if it has whose value is <= the corresponding value in the $arr_less_than
                        $s1 = array_reduce(
                            array_keys($sub),
                            function ($fail, $key) use ($sub, $arr_less_than) {
                                return $fail || $sub[$key] <= $arr_less_than[$key];
                            },
                            false
                        );
                        // This could be short-circuited above to avoid an unnecessary array_reduce call
                        return $c1 || !$s1;
                    },
                    false
                );
                echo "\t$y" . PHP_EOL;
                // Include the array value in the filter if there are any matching values
                return $y;
            }
        )
    );
}

print_r(getMatchingRowsAny($arr_less_than, $MasterArray, $BlackList));

作为一个练习(因为我是贪婪的惩罚)我使用foreach作为生成器和返回数组的函数呈现相同的方法 - 主要是为了说明foreach可能是更好的选择,肯定更简单:

// Implemented as a generator - The associated foreach that uses it follows
function generateMatchingRows($arr_less_than, $MasterArray, $BlackList)
{
    foreach ($MasterArray as $k => $v) {
        if (in_array($k, $BlackList)) {
            continue;
        }
        foreach ($v as $sub_array) {
            $match = true;
            foreach ($sub_array as $k1 => $v1) {
                if ($v1 <= $arr_less_than[$k1]) {
                    $match = false;
                    break;
                }
            }
            if ($match) {
                yield $k;
                break;
            }
        }
    }
}

foreach (generateMatchingRows($arr_less_than, $MasterArray, $BlackList) as $k) {
    echo $k . PHP_EOL; // Or push them onto an array
}

// Implemented as a function returning an array - classical approach - just return an array
function getMatchingRowsForEach($arr_less_than, $MasterArray, $BlackList)
{
    $rv = [];
    foreach ($MasterArray as $k => $v) {
        if (in_array($k, $BlackList)) {
            continue;
        }
        foreach ($v as $sub_array) {
            $match = true;
            foreach ($sub_array as $k1 => $v1) {
                if ($v1 <= $arr_less_than[$k1]) {
                    $match = false;
                    break;
                }
            }
            if ($match) {
                $rv[] = $k;
                break;
            }
        }
    }
    return $rv;
}

print_r(getMatchingRowsForEach($arr_less_than, $MasterArray, $BlackList));
相关问题