mike
mike

Reputation: 35

Function return type is wrong after if else expressions

I have the following function which returns a list of 8 elements or list:

def orderCost(orderItems: List[Double]) = {

if (orderItems.length <= 8) orderItems else orderItems.grouped(8).toList

}

So my question is that why my function is returning List[Any] instead of List[Double] or List[List[Double]]. Is there a bug 2.11.8 which i'm using.

orderItems can be one of the below:

orderItems: List[Double] = List(4.99, 8.99, 8.99, 8.99, 8.99, 8.99, 8.99, 8.99)

or

 orderItems: List[Double] = List(4.99, 8.99, 8.99, 8.99, 8.99, 8.99, 8.99, 8.99, 4.99, 8.99, 8.99, 8.99, 8.99, 8.99, 8.99, 8.99)

I want to a list of eight elements if order item length is 8 or create a multiple list from order item, where each sub list contains 8 elements max

Thanks

Upvotes: 0

Views: 80

Answers (3)

Tim
Tim

Reputation: 27356

The problem is that the only type that is compatible with both List[Double] and List[List[Double]] is List[Any], so that is the result type of the function. There are no union types (until 3.0) so you can't return List[Double] | List[List[Double]].

You can unpick the current return value with a match statement (but beware type erasure). Or you could return Either[List[Double], List[List[Double]] like this:

def orderCost(orderItems: List[Double]) = {
  if (orderItems.length <= 8) Left(orderItems) else Right(orderItems.grouped(8).toList)
}

orderCost(myItems) match {
  case Left(ld) => // Handle List[Double]
  case Right(lld) => // Handle List[List[Double]]
}

Upvotes: 1

Nagarjuna Pamu
Nagarjuna Pamu

Reputation: 14825

Just change the return of the function. grouped with take care of all cases.

def orderCost(orderItems: List[Double]): List[List[Double]] = 
   orderItems.grouped(8).toList

Scala REPL

scala> val l = (1 to 10)
l: scala.collection.immutable.Range.Inclusive = Range 1 to 10

scala> l.grouped(8).toList
res0: List[scala.collection.immutable.IndexedSeq[Int]] = List(Vector(1, 2, 3, 4, 5, 6, 7, 8), Vector(9, 10))

scala> val l = (1 to 4)
l: scala.collection.immutable.Range.Inclusive = Range 1 to 4

scala> l.grouped(8).toList
res1: List[scala.collection.immutable.IndexedSeq[Int]] = List(Vector(1, 2, 3, 4))

So, function looks like

scala> def orderCost(orderItems: List[Double]): List[List[Double]] = orderItems.grouped(8).toList
orderCost: (orderItems: List[Double])List[List[Double]]

scala> orderCost(List(1, 2, 3, 4))
res2: List[List[Double]] = List(List(1.0, 2.0, 3.0, 4.0))

scala> orderCost((1 to 20).toList.map(_.toDouble))
res4: List[List[Double]] = List(List(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0), List(9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0), List(17.0, 18.0, 19.0, 20.0))

Upvotes: 1

Manoj Kumar Dhakad
Manoj Kumar Dhakad

Reputation: 1892

You need not to check length, You can do directly like this

def orderCost(orderItems: List[Double]) = {

     orderItems.grouped(8).toList

  }

Sample Input 1:

val orderItems: List[Double] = List(4.99, 8.99, 8.99, 8.99, 8.99, 8.99, 8.99, 8.99, 8.99, 8.99, 8.99, 8.99, 8.99, 8.99, 8.99, 8.99, 8.99, 8.99, 8.99, 8.99)

Sample Output 1:

List(List(4.99, 8.99, 8.99, 8.99, 8.99, 8.99, 8.99, 8.99), List(8.99, 8.99, 8.99, 8.99, 8.99, 8.99, 8.99, 8.99), List(8.99, 8.99, 8.99, 8.99))

Sample Input 2:

val orderItems1: List[Double] = List(1,2,3,4,5.8)

Sample Output 2:

List(List(1.0, 2.0, 3.0, 4.0, 5.8))

Upvotes: 1

Related Questions