Loop through list to call different functions

Viewed 341

I have a list of integer, need to loop through the list and call different functions which all have the same input parameters, here is my code:

  def callRandomFunctions(config: config, prefix: String): ChainBuilder = {
    val randomList = Random.shuffle(List(1, 2, 3, 4))
    randomList.foreach { _ =>
      _ match {
        case 1 => func1(config, prefix)
        case 2 => func2(config, prefix)
        case 3 => func3(config, prefix)
        case 4 => func4(config, prefix)
      }
    }
  }

 def func1(config: config, prefix: String): ChainBuilder = {...}
 def func2(config: config, prefix: String): ChainBuilder = {...}
 def func3(config: config, prefix: String): ChainBuilder = {...}
 def func4(config: config, prefix: String): ChainBuilder = {...} 

and got these errors:

missing parameter type for expanded function
[error] The argument types of an anonymous function must be fully known. (SLS 8.5)
[error] Expected type was: ?
[error]         _ match {
[error]         ^


[error] type mismatch;
[error]  found   : Unit
[error]  required: io.gatling.core.structure.ChainBuilder
[error]     randomList.foreach {
[error]                        ^
[error] two errors found
4 Answers

Simply shuffle the functions and then call them directly.

def func1(config: config, prefix: String): ChainBuilder = ???
def func2(config: config, prefix: String): ChainBuilder = ???
def func3(config: config, prefix: String): ChainBuilder = ???
def func4(config: config, prefix: String): ChainBuilder = ???

def callRandomFunctions(config: config, prefix: String): Seq[ChainBuilder] =
  Random.shuffle(Seq(func1 _, func2 _, func3 _, func4 _))
        .map(_(config, prefix))

You can simply do this:

randomList.foreach {
    case 1 => func1(config, prefix)
    case 2 => func2(config, prefix)
    case 3 => func3(config, prefix)
    case 4 => func4(config, prefix)
}

and it will work as a pattern matching on number passed to foreach callback.

Another issue with your code is that you want to return ChainBuilder from callRandomFunctions but you're using foreach which is terminating operator returning Unit. You probably wanted to use map and change return type to List[ChainBuilder]:

def callRandomFunctions(config: Config, prefix: String): List[ChainBuilder] = {
    val randomList = Random.shuffle(List(1, 2, 3, 4))
    randomList.map {
        case 1 => func1(config, prefix)
        case 2 => func2(config, prefix)
        case 3 => func3(config, prefix)
        case 4 => func4(config, prefix)
    }
}

for a more gatling-y solution

def callRandomFunctions(config: config, prefix: String): ChainBuilder = {
  val randomList = Random.shuffle(List(1, 2, 3, 4))

  exec(session => session.set("randomList")
  .forEach("${randomList}", "currentVal") {
    doSwitch("${currentVal}") (
       1 -> exec(func1(config: config, prefix: String)),
       2 -> exec(func2(config: config, prefix: String)),
       3 -> exec(func3(config: config, prefix: String)),
       4 -> exec(func4(config: config, prefix: String))
    )
  } 

if the order of execution doesn't really need to be random you could also use a .roundRobinSwitch

You can execute the function by their name with reflection (although the performance isn't so great). You don't need the pattern matching and it's just another way of implementation:

You need to put all your function in a specific class:

case class FunctionsClass(config: config, prefix: String) {
  def func1(config: config, prefix: String): ChainBuilder = ???
  def func2(config: config, prefix: String): ChainBuilder = ???
  def func3(config: config, prefix: String): ChainBuilder = ???
  def func4(config: config, prefix: String): ChainBuilder = ???
}

Then, implement callRandomFunctions like this:

def callRandomFunctions(config: config, prefix: String):Unit = {
  val args = List(config, prefix)
  val argtypes = args.map(_.getClass)
  val functionsClassObj = FunctionsClass(config, prefix)
  val randomList = Random.shuffle(List(1, 2, 3, 4))

  val result = randomList.map{ i =>     
      val mtd = functionsClassObj.getClass.getMethod(s"func$i", argtypes: _*)
      Try {mtd.invoke(functionsClassObj, args: _*)}.recover { case _ => println("ERROR")}
  }

  result.filter(_.isSuccess).map(_.get))
}

This way you are calling your func method based on the ids in your shuffled list

Related