Convert a List into an Option if it is populated
Asked Answered
M

6

26

I have a method that should convert a list to an Option of an object, or None if the list is empty.

def listToOption(myList: List[Foo]): Option[Bar] = {
  if(myList.nonEmpty) Some(Bar(myList))
  else None
}

case class Bar(fooList: List[Foo]) {}

For some reason, my solution feels rather inelegant, and not the Scala way. It seems I should be able to use a method on List to do this sort of thing, but I can't wrap my head around it.

Is there a more Scala-like way to do this?

Marylou answered 30/1, 2015 at 20:42 Comment(3)
I first thought that you wanted the head of the list when present but then I re-read your question I really do not understand why you would want to do this. It's hard finding a idiomatic way to do stuff when it's not a common operation. It would be nice if you could clarify what you are going to use this functionality for.Serdab
From a wider perspective, it was already clear to me that there are some design problems in this class I'm working with, but I chose not to refactor the class and instead try to write something elegant given the weird restraints. My if-else solution merely felt lacking, and I thought there could be a better way to do it.Marylou
I've been doing Scala for about 9 months, and I truly find it to be awesome, but it's both a blessing and a curse that you can do stuff exactly how you want to do it. I would have refactored the crap out of that code. Well thanks for the clarification, and GLHF coding Scala!Serdab
L
32

Lee's answer is good, but I think this corresponds to the intention a bit more clearly:

Option(myList).filter(_.nonEmpty).map(Bar)
Linguistician answered 31/1, 2015 at 7:16 Comment(0)
N
20

Starting Scala 2.13, Option has a when builder:

Option.when(condition)(result)

which in our case gives:

Option.when(myList.nonEmpty)(Bar(myList))
// val myList = List[Int]()    =>    Option[Bar] = None
// val myList = List(1, 2)     =>    Option[Bar] = Some(Bar(List(1, 2)))

Also note Option.unless which promotes the opposite condition:

Option.unless(myList.isEmpty)(Bar(myList))
// val myList = List[Int]()    =>    Option[Bar] = None
// val myList = List(1, 2)     =>    Option[Bar] = Some(Bar(List(1, 2)))
Norfolk answered 23/1, 2019 at 13:16 Comment(0)
W
15
myList.headOption.map(_ => Bar(myList))
Willardwillcox answered 30/1, 2015 at 20:47 Comment(3)
The force is strong with this one.Marylou
@CoryKlein - I'm not sure this is actually better than an explicit match since it seems a bit messy to ignore the value.Willardwillcox
But the sheer brevity of it!Marylou
F
3

How about:

Some(myList) collect { case(l@hd::tl) => Bar(l) }

Seems pretty scala-esque to me.

Flossie answered 30/1, 2015 at 21:49 Comment(1)
You could also use case l if l.nonEmpty.Linguistician
A
2
import scalaz._; import Scalaz._
myList.toNel.map(Bar)

toNel - is "to non-empty list" here, it returns Option[NonEmptyList] for safety:

scala> case class Bar(a: NonEmptyList[Int])
defined class Bar

scala> List(1,2,3).toNel.map(Bar)
res64: Option[Bar] = Some(Bar(NonEmptyList(1, 2, 3)))

scala> List[Int]().toNel.map(Bar)
res65: Option[Bar] = None
Agone answered 30/1, 2015 at 21:3 Comment(0)
S
0

Let us give some imperative style to get the requested output, pls give a look below snippet. Hope will be helpful

def sequenceBase[A](a: List[Option[A]]): Option[List[A]] = {
  //match the list[option[A]]
  a match {
    case e: List[A] => {
      
      //this is similar to lift which helps to convert the Option to actual value.
      def map1(element: Option[A]): A = element match {
        case Some(a) => a
        case None => throw new IllegalArgumentException("None...!")
      }
      
      //this will help to return the list of values from the map1 return 
      Some(for (i <- a) yield map1(i))
    }
    
    //if one of the values is none we are not going to process further
    case List(None, _) => throw new IllegalArgumentException("Invalid")
  }
}

//actual runner
println(sequenceBase[Int](List(Some(1), Some(3), Some(3))))
Shoshone answered 22/9, 2023 at 18:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.