Сменить все целые числа в списке с помощью Scala

appcodix спросил: 13 июня 2018 в 10:08 в: scala

Если у меня есть метод swap, который может заменить два целых числа в списке:

def swap[E]: (List[E], Int, Int) => List[E] = (ls, i, j) => 
  ls.updated(i, ls(j)).updated(j, ls(i))

И теперь Я хочу поменять все целые числа списка, используя этот метод. Это означает, что результат должен быть таким:

swapAll(List(1,2,3)) == List(List(2,1,3), List(3,2,1), List(1,3,2))

Я подумал о чем-то вроде этого:

def swapAll: List[Int] => List[List[Int]] = ls => for(i <- 0 to ls.length; j <- i to ls.length) yield List(swap(ps, i, j))

Но это не работает , у кого-то есть идея?


1 ответ

Есть решение
Andrey Tyukin ответил: 13 июня 2018 в 10:24

Почти там.

def swap[E](ls: List[E], i: Int, j: Int): List[E] = {
  ls.updated(i, ls(j)).updated(j, ls(i))
}def swapAll(ps: List[Int]): List[List[Int]] = {
  val n = ps.size
  (for {
    i <- 0 until n
    j <- (i + 1) until n
  } yield swap(ps, i, j))(collection.breakOut)
}

Пример:

swapAll(List(1, 2, 3))
// List(List(2, 1, 3), List(3, 2, 1), List(1, 3, 2))

breakOut - это специальный явно вставленный . Это необходимо, потому что без него тип созданной коллекции - это какой-то странный CanBuildFrom, полученный из IndexedSequence 0 until n, но вы хотите Range вместо этого.

Leo C ответил: 13 июня 2018 в 10:34
Хороший, отличный вариант для breakOut!
Andrey Tyukin ответил: 13 июня 2018 в 10:38
@appcodix Вызов toList в конце: (for { ... } yield ...).toList. Но это неэффективно, потому что он создает ненужную промежуточную коллекцию, которая не является List. Кроме того, попробуйте (0 until n).toList на генераторе.
appcodix ответил: 13 июня 2018 в 10:35
Большое спасибо. Очень изящный, но как бы это сделать без разрыва?