9

I am looking for the scala way to give all permutations without repetitions. I know there are some postings on this site already but they seem to have a slightly different problem.

I am searching for all permutations with repetitions. For example:

combine(List('A','C','G'))

Should yield:

List(List('A'.'A','A'),List('A'.'A','C'),List('A'.'A','G'),List('A'.'C','A'),
List('A'.'C',''C), ... List('G'.'G','G')

I am sorry if my problem is already solved but I was not able to find it.

Thanks in advance.

EDIT:

My own approach (doesn't compile):

def combine(size: Int = sym.length) : List[List[T]] = {
  size match {
    case 0 => List()
    case 1 => sym.toList.map(List(_))
    case _ => for (el <- sym) yield el :: combine(size-1)
  }
}

sym is an array member of a class which contains all the symbols to be combined.

uoyilmaz
  • 3,035
  • 14
  • 25
peri4n
  • 1,389
  • 13
  • 24

7 Answers7

12

With Scalaz:

scala> import scalaz._
import scalaz._

scala> import Scalaz._
import Scalaz._

scala> def combine[A](xs: List[A]): List[List[A]] = {
     |   xs.replicate[List](xs.size).sequence
     | }
combine: [A](xs: List[A])List[List[A]]

scala> combine(List('A', 'C', 'G'))
res47: List[List[Char]] = List(List(A, A, A), List(A, A, C), List(A, A, G), List
(A, C, A), List(A, C, C), List(A, C, G), List(A, G, A), List(A, G, C), List(A, G
, G), List(C, A, A), List(C, A, C), List(C, A, G), List(C, C, A), List(C, C, C),
 List(C, C, G), List(C, G, A), List(C, G, C), List(C, G, G), List(G, A, A), List
(G, A, C), List(G, A, G), List(G, C, A), List(G, C, C), List(G, C, G), List(G, G
, A), List(G, G, C), List(G, G, G))
missingfaktor
  • 90,905
  • 62
  • 285
  • 365
  • This is much cuter in Haskell: `combine = sequence . (replicate =<< length)`. – missingfaktor Sep 23 '11 at 15:35
  • This doesn't seem to work anymore with the latest version of Scalaz. It seems there's only a `replicateM(n: Int)` method in the library, but no `replicate[List](n: Int)` method. – William DeMeo Nov 09 '17 at 18:23
  • @WilliamDeMeo, this answer was written more than six years ago. Nothing in Scalaz is the same any more. – missingfaktor Nov 10 '17 at 23:15
  • 1
    yes, I see that... still worth pointing out, don't you think? ...so people don't waste time trying this solution as is? Perhaps you would consider updating your solution so that it's still helpful. – William DeMeo Nov 11 '17 at 18:50
  • @WilliamDeMeo, alas, I no longer have that kind of time these days. :) But please feel free to update it per the new version! – missingfaktor Nov 13 '17 at 11:18
8
def combinations(size: Int = sym.length) : List[List[T]] = {
    if (size == 0)
        List(List())
    else {
        for {
            x  <- sym.toList
            xs <- combinations(size-1)
        } yield x :: xs
    }
}
hammar
  • 138,522
  • 17
  • 304
  • 385
8

This should work:

val input = List('A','C','G')

(input ++ input ++ input) combinations(3) toList
soc
  • 27,983
  • 20
  • 111
  • 215
  • 1
    +1 Or when you don't know the size of the original list: ```(input.map(_ => input)).flatten.combinations(3).toList``` – opyate Sep 23 '12 at 20:08
  • @opyate Nice :). It could be even shortened to `input.flatMap(_ => input).combinations(3).toList`. My closest different not-so-nice approach is `Seq.fill(input.size)(input).flatten.combinations(3).toList`. – monnef Feb 02 '15 at 10:58
  • This does not match the OP's specification. For example, your result will include `List('A', 'A', 'C')`, as it should, but it will not include `List('A', 'C', 'A')`, nor `List('C', 'A', 'A')`. The OP wants all three-element lists, where the ordering of elements in each list matters. – William DeMeo Nov 09 '17 at 06:21
  • Put another way, the OP is asking for permutations, not just combinations. – bjmc Nov 14 '18 at 12:27
3
scala> def comb(s:String)=(s * s.length).combinations(s.length)
comb: (s: String)Iterator[String]

scala> comb("ACG").toList
res16: List[String] = List(AAA, AAC, AAG, ACC, ACG, AGG, CCC, CCG, CGG, GGG)

And if you wanted the resulting permutations:

scala> comb("ACG").flatMap(_.toSeq.permutations.toList).toList
res11: List[Seq[Char]] = List(AAA, AAC, ACA, CAA, AAG, AGA, GAA, ACC, CAC, CCA, ACG, AGC, CAG, CGA, GAC, GCA, AGG, GAG, GGA, CCC, CCG, CGC, GCC, CGG, GCG, GGC, GGG)

You can leave out the toList but it's there so you can see the results.

Mark Lister
  • 1,103
  • 6
  • 16
2

It seems no one has suggested the easiest---or, at least, easiest to read---solution. It is

myList = List("A", "C", "G")
for {
  i <- myList
  j <- myList
  k <- myList
} yield List(i,j,k)

(This is syntactic sugar for the following composition of maps:

myList.flatMap(i => myList.flatMap(j => myList.map(k => List(i,j,k))))

to which the Scala compiler translates the above for expression.)

0

In ScalaZ 7

import scalaz._
import Scalaz._
def combinine[T](l: List[T]) = l.replicateM(l.size)
Viktor Hedefalk
  • 3,572
  • 3
  • 33
  • 48
0

Just making a more generic answers, from @opyate and @monnef:

// considering that we want a permutation_size
List.fill(permutation_size)(input).flatten.combinations(permutation_size).toList

This will generate the permutation with repetition with size permutation_size:

val a = List.fill(2)(List("A","B","C")).flatten.combinations(2).toList
a: List[List[String]] = List(List(A, A), List(A, B), List(A, C), List(B, B), List(B, C), List(C, C))

and

val a = List.fill(3)(List("A","B","C")).flatten.combinations(3).toList
a: List[List[String]] = List(List(A, A, A), List(A, A, B), List(A, A, C), List(A, B, B), List(A, B, C), List(A, C, C), List(B, B, B), List(B, B, C), List(B, C, C), List(C, C, C))
Adriano Almeida
  • 5,186
  • 5
  • 20
  • 28
  • This is not a solution. Your result doesn't match the OP's specification. Notice you won't have the entry `List(A, C, A)`, but the OP wants that included in the result. – William DeMeo Nov 09 '17 at 18:18