list - recorrer - ¿Cómo hacer un conjunto anidado en Scala de una manera idiomática?
scala introduccion (2)
¿Hay una manera más idiomática de cambiar una secuencia anidada de secuencias en un conjunto anidado de conjuntos?
def toNestedSet[T](tsss: Seq[Seq[Seq[T]]]): Set[Set[Set[T]]] =
tsss.map(_.map(_.toSet).toSet).toSet
¿Es posible implementar una función que funcione con listas de cualquier profundidad?
Para abordar la segunda parte de su pregunta (procesar una lista de profundidad arbitraria), algo así podría funcionar (la borradura de tipo se interpone un poco):
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
})
}
Nota: rápido y sucio: funciona, pero es bastante fácil de romper :)
Editar: el elenco fue redundante
En realidad, esto no está nada mal (ver mi respuesta aquí a una pregunta similar para una discusión adicional de este enfoque):
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)
Y entonces:
scala> println(setsify(Seq(Seq(Seq(Seq(1)), Seq(Seq(2, 3))))))
Set(Set(Set(Set(1)), Set(Set(2, 3))))
Estáticamente escrito como un Set[Set[Set[Set[[Int]]]]
y todo.
Bueno, mentí un poco. El <:!<
arriba no está realmente en la biblioteca estándar. Sin embargo, está en Shapeless o puedes definirlo muy fácilmente:
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!")
Y eso es realmente todo.