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

报告相同问题?

悬赏问题

  • ¥100 set_link_state
  • ¥15 虚幻5 UE美术毛发渲染
  • ¥15 CVRP 图论 物流运输优化
  • ¥15 Tableau online 嵌入ppt失败
  • ¥100 支付宝网页转账系统不识别账号
  • ¥15 基于单片机的靶位控制系统
  • ¥15 真我手机蓝牙传输进度消息被关闭了,怎么打开?(关键词-消息通知)
  • ¥15 装 pytorch 的时候出了好多问题,遇到这种情况怎么处理?
  • ¥20 IOS游览器某宝手机网页版自动立即购买JavaScript脚本
  • ¥15 手机接入宽带网线,如何释放宽带全部速度