避免PHP中的嵌套循环

时间:2019-02-18 06:13:51

标签: php laravel loops foreach refactoring

我正在编写一个方法,该方法需要一个$topicNames数组和一个$app数组,并将每个$app$topicNames串联起来,如下所示:

public function getNotificationTopicByAppNames(array $topicNames, array $apps)
    {
        $topics = [];

        foreach ($topicNames as $topicName) {
            foreach ($apps as $app) {
                $topic = $app . '_' . $topicName;

                $topics[] = $topic;
            }
        }

        return $topics;
    }
}

输入和结果如下...

$topicNames = [
    'one_noti',
    'two_noti',
    'three_noti'
];

$apps = [
    'one_app',
    'two_app'
];

// The return result of the method will be like the following

[
    'one_app_one_noti', 
    'two_app_one_noti',
    'one_app_two_noti', 
    'two_app_two_noti',
    'one_app_three_noti', 
    'two_app_three_noti'
]

我的问题是代替嵌套循环,还有其他方法吗?为什么要避免嵌套循环?因为目前,我有$topic。稍后,我可能要添加languageslocations等...

我知道我可以使用map, reduce, array_walks, each那些基本上是一个接一个地进行的操作。可以替代我可以使用的另一种替代方法吗?我可以更改其他数据类型而不是数组。

3 个答案:

答案 0 :(得分:2)

如果您不关心订单,可以使用此

function getNotificationTopicByAppNames(array $topicNames, array $apps)
{
    $topics = [];

    foreach($apps as $app){
        $topics = array_merge($topics, preg_filter('/^/', $app.'_', $topicNames));
    }

    return $topics;
}

print_r(getNotificationTopicByAppNames($topicNames,$apps));

输出

Array
(
    [0] => one_app_one_noti
    [1] => one_app_two_noti
    [2] => one_app_three_noti
    [3] => two_app_one_noti
    [4] => two_app_two_noti
    [5] => two_app_three_noti
)

Sandbox

您还可以切换循环,并使用$代替后缀而不是前缀。事实证明这与您的顺序相同。我想到将前缀作为删除循环的一种方式。然后我想为什么不翻转它。

 function getNotificationTopicByAppNames(array $topicNames, array $apps)
{
    $topics = [];

    foreach($topicNames as $topic){
        $topics = array_merge($topics, preg_filter('/$/', '_'.$topic, $apps));
    }

    return $topics;
}

print_r(getNotificationTopicByAppNames($topicNames,$apps));

输出

 Array
(
    [0] => one_app_one_noti
    [1] => two_app_one_noti
    [2] => one_app_two_noti
    [3] => two_app_two_noti
    [4] => one_app_three_noti
    [5] => two_app_three_noti
)

Sandbox

这里的诀窍是使用preg_filter

http://php.net/manual/en/function.preg-filter.php

  

preg_filter —执行正则表达式搜索并替换

因此,我们以^开头或$结尾进行搜索,该搜索不会捕获要替换的任何内容,然后我们只添加想要的内容。当我想给整个数组添加前缀等时,我就使用过此方法。

我无法在类中对其进行测试,因此我将其设置为常规函数,因此请根据需要进行调整。

干杯!

答案 1 :(得分:1)

您可以使用:

<?php 

    public function mergeStacks(...$stacks)
    {
        $allStacks = call_user_func_array('array_merge', $stacks);
        return $this->concatString($allStacks);

    }

    private function concatString(&$stack, $index = 0, &$result = [])
    {
        if(count($stack) == 0){
            return '';
        }

        if($index  == count($stack)){
            return $result;
        }



        array_walk($stack, function($value, $key) use($index, &$result, $stack){
            if($key > $index){
                array_push($result, $stack[$index] . '_' . $value);
            }
        });
        $index =  $index + 1;

        return $this->concatString($stack, $index, $result);
    }

然后,当您想要获取数组时,无论您是否有语言或主题等,都可以:

$this->mergeStacks($languages, $topics, $locations, .....);

其中$ languages,$ topics,$ locations是简单数组。

答案 2 :(得分:0)

请尝试以下操作,而不是仅接受主题名称参数:

function getNotificationTopicByAppNames(array $apps, array ...$names)
{
    $topics = [];
    foreach ($names as $nameArray) {
        foreach ($nameArray as $topicName) {
            foreach ($apps as $app) {
                $topic = $app . '_' . $topicName;

                $topics[] = $topic;
            }
        }
    }

    return $topics;
}



$topicNames = [
    'one_noti',
    'two_noti',
    'three_noti'
];

$languagesNames = [
    'test_en',
    'test_other',
    'test_other2'
];

$apps = [
    'one_app',
    'two_app'
];

print_r(getNotificationTopicByAppNames($apps,$topicNames,$languagesNames));

您可以将任意数量的数组传递给数组。