Search code examples
scalapermutation

Code to enumerate permutations in Scala


I coded a function to enumerate all permutations of a given list. What do you think of the code below?

def interleave(x:Int, l:List[Int]):List[List[Int]] = {
  l match { 
    case Nil => List(List(x))
    case (head::tail) =>
      (x :: head :: tail) :: interleave(x, tail).map(head :: _)
  }
}

def permutations(l:List[Int]):List[List[Int]] = {
  l match {
    case Nil => List(List())
    case (head::tail) =>
      for(p0 <- permutations(tail); p1 <- interleave(head, p0)) yield p1
  }
}

Solution

  • Given a Seq, one can already have permutations by invoking the permutations method.

    scala> List(1,2,3).permutations.mkString("\n")
    res3: String = 
    List(1, 2, 3)
    List(1, 3, 2)
    List(2, 1, 3)
    List(2, 3, 1)
    List(3, 1, 2)
    List(3, 2, 1)
    

    Furthermore there is also a method for combinations:

    scala> List(1,2,3).combinations(2).mkString("\n")
    res4: String = 
    List(1, 2)
    List(1, 3)
    List(2, 3)
    

    Regarding your implementation I would say three things:

    (1) Its good looking

    (2) Provide an iterator (which is the std collections approach that allows to discard elements). Otherwise, you can get lists with 1000! elements which may not fit in memory.

    scala> val longList = List((1 to 1000):_*)
    longList: List[Int] = List(1, 2, 3,...
    
    
    scala> permutations(longList)
    java.lang.OutOfMemoryError: Java heap space
        at scala.collection.immutable.List.$colon$colon(List.scala:67)
        at .interleave(<console>:11)
        at .interleave(<console>:11)
        at .interleave(<console>:11)
    

    (3) You should remove duplicated permutations (as observed by Luigi), since :

    scala> permutations(List(1,1,3))
    res4: List[List[Int]] = List(List(1, 1, 3), List(1, 1, 3), List(1, 3, 1), List(1, 3, 1), List(3, 1, 1), List(3, 1, 1))
    
    scala> List(1,1,3).permutations.toList
    res5: List[List[Int]] = List(List(1, 1, 3), List(1, 3, 1), List(3, 1, 1))