General extraction of a tuple with option [A]?

Given the function f, which, given the 2-tuple Option[A], puts non-empty elements of the set into output List[A]:

  def f[A](xs: (Option[A], Option[A])): List[A] = xs match {
    case (Some(x), Some(y)) => List(x, y)
    case (None,    Some(y)) => List(y)
    case (Some(x), None)    => List(x)
    case (None,    None)    => List.empty
  }

How can I write a general f, i.e. fGenthat will handle any tuple size, i.e. 2 to N?

Perhaps I can use formless?

+4
source share
3 answers

Here is my (not perfect) solution:

@ object Tuple2List {
    import shapeless._
    import syntax.std.tuple._
    import ops.hlist.ToTraversable
    trait Imp[A] {
      def apply[P <: Product, L <: HList](p: P)
               (implicit gen: Generic.Aux[P, L], 
                lub: LUBConstraint[L, Option[A]], 
                trav: ToTraversable.Aux[L, List, Option[A]]): List[A] =
        gen.to(p).toList.flatMap(_.toList)
    }
    def apply[A] = new Imp[A]{ }
  }
defined object Tuple2List
@ val xs = (Option(1), None, Option(2))
xs: (Option[Int], None.type, Option[Int]) = (Some(1), None, Some(2))

@ Tuple2List[Int](xs)
res9: List[Int] = List(1, 2)
@ val ys = (Option(1), None, Option(2), None, Option(3))
ys: (Option[Int], None.type, Option[Int], None.type, Option[Int]) = (Some(1), None, Some(2), None, Some(3))
@ Tuple2List[Int](ys)
res11: List[Int] = List(1, 2, 3)

Note that you need the pass type parameter Ato make the scala compiler happy.

+3
source

@Eastsun, . @Eastsun , list.map(ev) .

def tuple2list[P <: Product, L <: HList, Lub, A](p: P)(
  implicit gen: Generic.Aux[P, L],
  toList: ToList[L, Lub],
  ev: Lub <:< Option[A]
): List[A] =
  gen.to(p).toList.map(ev).flatten

val xs = (Option(1), None, Option(2))
println(tuple2list(xs)) // List(1, 2)

Product List flatten :

def tuple2list[P <: Product, L <: HList, Lub](p: P)(
  implicit gen: Generic.Aux[P, L],
  toList: ToList[L, Lub]
): List[Lub] =
  gen.to(p).toList

val xs = (Option(1), None, Option(2))
println(tuple2list(xs).flatten) // List(1, 2)
+2

The following code works with caveats:

may improve by

  • enter a function of ftype safe (due to erasing the type limited Option)
  • avoid casting with asInstanceOf

/**
 * param xs: Tuple of variable size (upto 22)
 */

def f[A](xs: Product): List[A] = xs.productIterator.toList.flatMap(_.asInstanceOf[Option[A]])

val tuple = (Some(1), Some(2), None, Some(3))
f[Int](tuple) // List(1, 2, 3)
+1
source

Source: https://habr.com/ru/post/1650437/


All Articles