subconjuntos - Cómo generar el conjunto de potencia de un conjunto en Scala
conjunto potencia propiedades (8)
Aquí está una de las formas más interesantes de escribirlo:
import scalaz._, Scalaz._
def powerSet[A](xs: List[A]) = xs filterM (_ => true :: false :: Nil)
Que funciona como se espera:
scala> powerSet(List(1, 2, 3)) foreach println
List(1, 2, 3)
List(1, 2)
List(1, 3)
List(1)
List(2, 3)
List(2)
List(3)
List()
Vea por ejemplo este hilo de discusión para una explicación de cómo funciona.
(Y como señala Debilski en los comentarios, ListW
también proxenetea el conjunto de powerset
en List
, pero eso no es divertido).
Tengo un conjunto de elementos de algún tipo y quiero generar su conjunto de energía.
Busqué en la web y no pude encontrar ningún código de Scala que aborde esta tarea específica.
Esto es lo que se me ocurrió. Le permite restringir la cardinalidad de los conjuntos producidos por el parámetro de longitud.
def power[T](set: Set[T], length: Int) = {
var res = Set[Set[T]]()
res ++= set.map(Set(_))
for (i <- 1 until length)
res = res.map(x => set.map(x + _)).flatten
res
}
Esto no incluirá el conjunto vacío. Para lograr esto, tendría que cambiar la última línea del método simplemente a res + Set ()
¿Alguna sugerencia de cómo se puede lograr esto en un estilo más funcional?
Aquí hay otra versión (perezosa) ... ya que estamos recopilando formas de computar el conjunto de energía, pensé en agregarlo:
def powerset[A](s: Seq[A]) =
Iterator.range(0, 1 << s.length).map(i =>
Iterator.range(0, s.length).withFilter(j =>
(i >> j) % 2 == 1
).map(s)
)
Aquí hay una solución simple y recursiva que usa una función auxiliar:
def concatElemToList[A](a: A, list: List[A]): List[Any] = (a,list) match {
case (x, Nil) => List(List(x))
case (x, ((h:List[_]) :: t)) => (x :: h) :: concatElemToList(x, t)
case (x, (h::t)) => List(x, h) :: concatElemToList(x, t)
}
def powerSetRec[A] (a: List[A]): List[Any] = a match {
case Nil => List()
case (h::t) => powerSetRec(t) ++ concatElemToList(h, powerSetRec (t))
}
así que la llamada de
powerSetRec(List("a", "b", "c"))
dará el resultado
List(List(c), List(b, c), List(b), List(a, c), List(a, b, c), List(a, b), List(a))
Observe que si tiene un conjunto S
y otro conjunto T
donde T = S ∪ {x}
(es decir, T
es S
con un elemento agregado), entonces el conjunto de potencias de T
- P(T)
- puede expresarse en términos de P(S)
x
como sigue:
P(T) = P(S) ∪ { p ∪ {x} | p ∈ P(S) }
Es decir, puede definir el conjunto de poderes de forma recursiva (observe cómo esto le da el tamaño del conjunto de poderes de forma gratuita, es decir, agregar 1 elemento duplica el tamaño del conjunto de poderes). Entonces, puedes hacer esto en forma recursiva en scala de la siguiente manera:
scala> def power[A](t: Set[A]): Set[Set[A]] = {
| @annotation.tailrec
| def pwr(t: Set[A], ps: Set[Set[A]]): Set[Set[A]] =
| if (t.isEmpty) ps
| else pwr(t.tail, ps ++ (ps map (_ + t.head)))
|
| pwr(t, Set(Set.empty[A])) //Powerset of ∅ is {∅}
| }
power: [A](t: Set[A])Set[Set[A]]
Entonces:
scala> power(Set(1, 2, 3))
res2: Set[Set[Int]] = Set(Set(1, 2, 3), Set(2, 3), Set(), Set(3), Set(2), Set(1), Set(1, 3), Set(1, 2))
En realidad, se ve mucho mejor haciendo lo mismo con una List
(es decir, un ADT recursivo):
scala> def power[A](s: List[A]): List[List[A]] = {
| @annotation.tailrec
| def pwr(s: List[A], acc: List[List[A]]): List[List[A]] = s match {
| case Nil => acc
| case a :: as => pwr(as, acc ::: (acc map (a :: _)))
| }
| pwr(s, Nil :: Nil)
| }
power: [A](s: List[A])List[List[A]]
Parece que nadie lo sabía en julio, pero hay un método incorporado: subsets
.
scala> Set(1,2,3).subsets foreach println
Set()
Set(1)
Set(2)
Set(3)
Set(1, 2)
Set(1, 3)
Set(2, 3)
Set(1, 2, 3)
Puede ser tan simple como:
def powerSet[A](xs: Seq[A]): Seq[Seq[A]] =
xs.foldLeft(Seq(Seq[A]())) {(sets, set) => sets ++ sets.map(_ :+ set)}
Implementación recursiva:
def powerSet[A](xs: Seq[A]): Seq[Seq[A]] = {
def go(xsRemaining: Seq[A], sets: Seq[Seq[A]]): Seq[Seq[A]] = xsRemaining match {
case Nil => sets
case y :: ys => go(ys, sets ++ sets.map(_ :+ y))
}
go(xs, Seq[Seq[A]](Seq[A]()))
}
Todas las otras respuestas parecían un poco complicadas, aquí hay una función simple:
def powerSet (l:List[_]) : List[List[Any]] =
l match {
case Nil => List(List())
case x::xs =>
var a = powerSet(xs)
a.map(n => n:::List(x)):::a
}
asi que
powerSet(List(''a'',''b'',''c''))
producirá el siguiente resultado
res0: List[List[Any]] = List(List(c, b, a), List(b, a), List(c, a), List(a), List(c, b), List(b), List(c), List())
Utilice la función de combinations
incorporada:
val xs = Seq(1,2,3)
(0 to xs.size) flatMap xs.combinations
// Vector(List(), List(1), List(2), List(3), List(1, 2), List(1, 3), List(2, 3),
// List(1, 2, 3))
Tenga en cuenta que hice trampa y usé un Seq
, porque por razones desconocidas, las combinations
se definen en SeqLike
. Así que con un conjunto, necesitas convertir a / desde un Seq
:
val xs = Set(1,2,3)
(0 to xs.size).flatMap(xs.toSeq.combinations).map(_.toSet).toSet
//Set(Set(1, 2, 3), Set(2, 3), Set(), Set(3), Set(2), Set(1), Set(1, 3),
//Set(1, 2))