Search code examples
scalascala-2.11

How to better partition valid or invalid inputs


Given a list of inputs that could be valid or invalid, is there a nice way to transform the list but to fail given one or more invalid inputs and, if necessary, to return information about those invalid inputs? I have something like this, but it feels very inelegant.

def processInput(inputList: List[Input]): Try[List[Output]] = {
    inputList map { input =>
        if (isValid(input)) Left(Output(input))
        else Right(input)
    } partition { result =>
        result.isLeft
    } match {
        case (valids, Nil) => 
            val outputList = valids map { case Left(output) => output }
            Success(outputList)
        case (_, invalids) => 
            val errList =  invalids map { case Right(invalid) => invalid }
            Failure(new Throwable(s"The following inputs were invalid: ${errList.mkString(",")}")) 
    }
}

Is there a better way to do this?


Solution

  • I think you can simplify your current solution quite a bit with standard scala:

      def processInput(inputList: List[Input]): Try[List[Output]] = 
        inputList.partition(isValid) match {
         case (valids, Nil) => Success(valids.map(Output))
         case (_, invalids) => Failure(new Throwable(s"The following inputs were invalid: ${invalids.mkString(",")}"))
      }
    

    Or, you can have a quite elegant solution with scalactic's Or.

      import org.scalactic._
    
      def processInputs(inputList: List[Input]): List[Output] Or List[Input] = 
        inputList.partition(isValid) match {
         case (valid, Nil) => Good(valid.map(Output))
         case (_, invalid) => Bad(invalid)
      }
    

    The result is of type org.scalactic.Or, which you then have to match to Good or Bad. This approach is more useful if you want the list of invalid inputs, you can match it out of Bad.