1

I am writing a method which takes an array of $topicNames and an array of $app and concatenates each $app to $topicNames like the following

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

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

                $topics[] = $topic;
            }
        }

        return $topics;
    }
}

The input and result are like the following...

$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'
]

My question is instead of doing nested loops, is there any other way I can do? Why do I want to avoid nested loops? Because currently, I have $topic. Later, I might want to add languages, locations etc...

I know I can use map, reduce, array_walks, each those are basically going through one by one. Instead of that which another alternative way I can use? I am okay changing different data types instead of the array as well.

common sense
  • 3,775
  • 6
  • 22
  • 31
Set Kyar Wa Lar
  • 4,488
  • 4
  • 30
  • 57

3 Answers3

2

If you dont care about the order you can use this

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

Output

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

You can also switch loops and use the $ instead to postfix instead of prefix. Which turns out to be in the same order you had. I thought of prefixing as a way to remove the loop. Then i thought why not flip it.

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

Output

 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

The trick here is using preg_filter.

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

preg_filter — Perform a regular expression search and replace

So we search with ^ start or $ end which doesn't capture anything to replace and then we just add on what we want. I've used this before when I wanted to prefix a whole array with something, etc.

I couldn't test it in a class, so I made it a regular function, so adjust as needed.

Cheers!

ArtisticPhoenix
  • 21,464
  • 2
  • 24
  • 38
1

You can use :

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

And then when you want to get the array, no matter if you have languages or topics etc, you can just do :

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

Where $languages, $topics, $locations are simple arrays.

Mihir Bhende
  • 8,677
  • 1
  • 30
  • 37
0

Instead of accepting only topics name parameter try something like this:

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

you can pass any number of arrays to array.

Supun Praneeth
  • 3,087
  • 2
  • 30
  • 33