Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make a nested toSet in scala in an idiomatic way?

Is there a more idiomatic way to change a nested sequence of sequences into a nested set of sets?

def toNestedSet[T](tsss: Seq[Seq[Seq[T]]]): Set[Set[Set[T]]]  = 
   tsss.map(_.map(_.toSet).toSet).toSet

Is it possible to implement a function which would work with lists of any depth?

like image 482
goozez Avatar asked Feb 11 '14 14:02

goozez


2 Answers

This actually isn't too bad at all (see my answer here to a similar question for some additional discussion of this approach):

trait Setsifier[I, O] { def apply(i: I): O }

object Setsifier {
  def apply[I, O](f: I => O) = new Setsifier[I, O] { def apply(i: I) = f(i) }

  implicit def base[I](implicit ev: I <:!< Seq[_]) = apply((_: Seq[I]).toSet)

  implicit def rec[I, O](implicit s: Setsifier[I, O]) =
    apply((_: Seq[I]).map(s(_)).toSet)
}

def setsify[I, O](i: I)(implicit s: Setsifier[I, O]) = s(i)

And then:

scala> println(setsify(Seq(Seq(Seq(Seq(1)), Seq(Seq(2, 3))))))
Set(Set(Set(Set(1)), Set(Set(2, 3))))

Statically typed as a Set[Set[Set[Set[[Int]]]] and all.

Well, I lied a little bit. The <:!< above isn't actually in the standard library. It is in Shapeless, though, or you can very, very easily define it yourself:

trait <:!<[A, B]

implicit def nsub[A, B] : A <:!< B = new <:!<[A, B] {}
implicit def nsubAmbig1[A, B >: A] : A <:!< B = sys.error("Don't call this!")
implicit def nsubAmbig2[A, B >: A] : A <:!< B = sys.error("Don't call this!")

And that's really all.

like image 148
Travis Brown Avatar answered Nov 10 '22 19:11

Travis Brown


To address the second part of your question (processing a list of arbitrary depth), something like this would work (type erasure gets in the way a bit):

  def toNestedSet(ts: Seq[Any]): Set[Any] = {
    ts.foldLeft[Set[Any]](Set())((acc, b) => b match {
        case s: Seq[_] => acc + toNestedSet(s)
        case x => acc + x
    })
  } 

Note: quick and dirty -- it works, but fairly easy to break :)

Edit: The cast was redundant

like image 35
James Adam Avatar answered Nov 10 '22 21:11

James Adam