douzoudang1511 2017-08-01 19:13
浏览 48
已采纳

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

I want to get sub array keys from array by less than values.
This is an example:

$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)),
);

Now I need to get sub array keys from $MasterArray by less than $arr_less_than if the sub array key is not in the array $BlackList.

For the above example, the result must return array(12,13).

Note: I don't want to use a foreach loop

  • 写回答

1条回答 默认 最新

  • duanbu9345 2017-08-01 23:32
    关注

    There are 2 solutions here - one for all sub-arrays meet the criteria, and one for any sub-array meets the criteria (which it seems is what the OP had in mind). At the end, there are foreach based solutions for the latter case where ANY sub-array meets the criteria.

    If I understand the problem correctly, the goal is to identify rows in MasterArray where all of the sub-arrays have values that are greater than the corresponding value in $arr_less_than.

    The OP does not want to use foreach (See the end of the answer for foreach based answers which are much simpler) - which may actually produce a more efficient version because it can avoid unnecessary compares and save some cycles, so here is a heavily annotated version using array functions.

    I've excluded the data which can be copied from OP's post:

    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));
    

    The basic idea is to generate a list of keys from the outermost array - so we iterate over them with array_filter. Then we exclude those with a key in the blacklist. Rows that arent in the blacklist, are reduced into an integer by iterating over each sub=arrays values and comparing them positon-wise against $arr_less_than and adding 1 for each value that fails to be greater than the corresponding member in $arr_less_than. Then those values are summed for all of the members in the MasterArray row. If the result is zero, then the row passes. Finally, the ultimate result is passed to array_values to normalize the resulting array.

    Note that this requires that all values be compared, even if the first sub-value in the first sub-array fails. For that reason a foreach approach that can escape may be more efficient.

    This is essentially the same method without comments and couple of shortcuts:

    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
                    );
                }
            )
        );
    }
    

    Some of the methods in array_reduce are short-circuited using ?: operator since the actual count is irrelevant. Once the count exceeds zero, the row fails, regardless.

    Here is similar code if the criterion is that AT LEAST ONE sub-array has all members greater than the reference array.

    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));
    

    As an exercise (and because I'm a glutton for punishment) I rendered the same methods using foreach as both a generator and a function returning an array - mostly to illustrate that foreach may be the better choice, and is definitely simpler:

    // 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));
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 乌班图ip地址配置及远程SSH
  • ¥15 怎么让点阵屏显示静态爱心,用keiluVision5写出让点阵屏显示静态爱心的代码,越快越好
  • ¥15 PSPICE制作一个加法器
  • ¥15 javaweb项目无法正常跳转
  • ¥15 VMBox虚拟机无法访问
  • ¥15 skd显示找不到头文件
  • ¥15 机器视觉中图片中长度与真实长度的关系
  • ¥15 fastreport table 怎么只让每页的最下面和最顶部有横线
  • ¥15 R语言卸载之后无法重装,显示电脑存在下载某些较大二进制文件行为,怎么办
  • ¥15 java 的protected权限 ,问题在注释里