Метод +
в IndexedSeq
используется для создания новой последовательности, содержащей один дополнительный заданный элемент, но вы хотите создать последовательность, содержащую дополнительную последовательность. Метод для этого ++
, поэтому ваша последняя строка должна выглядеть следующим образом:
(n.take(pivot) :+ n(successor)) ++
((n.slice(pivot+1, successor):+ n(pivot)) ++ n.drop(successor+1)).reverse
Вы видите это странное сообщение компилятора об ожидаемом String
, потому что подпись +
не совпадает, и, таким образом, включается явное преобразование, используемое для конкатенации строк (это преобразование существует, потому что оно позволяет вам написать что-то вроде List(8) + " Test"
).
РЕДАКТИРОВАТЬ: Обобщение по типам последовательности упорядоченных элементов:
Как я уже говорил в комментариях, обобщение последовательностей немного сложнее. В дополнение к вашему типу элемента A
вам потребуется еще один тип CC[X] <: SeqLike[X,CC[X]]
, представляющий последовательность. Обычно C <: SeqLike[A,C]
было бы достаточно, но средство вывода типов не понравилось бы такому (вам всегда нужно было бы передавать типы A
и C
при вызове этого метода).
Если вы просто измените свою подпись таким образом, компилятор будет жаловаться на то, что для нее требуется неявный параметр CanBuildFrom[CC[A],A,CC[A]]
, поскольку он необходим, например. по методу reverse
. Этот параметр используется для создания одного типа последовательности из другого - просто найдите на сайте несколько примеров того, как он используется API коллекций.
Окончательный результат будет выглядеть так:
import collection.SeqLike
import collection.generic.CanBuildFrom
def nextPermutation[A, CC[X] <: SeqLike[X,CC[X]]](n: CC[A])(
implicit ord: Ordering[A], bf: CanBuildFrom[CC[A],A,CC[A]]): CC[A] = {
import ord._
// call toSeq to avoid having to require an implicit CanBuildFrom for (A,A)
val pivot = n.toSeq.zip(n.tail.toSeq).lastIndexWhere{
case (first, second) => first < second
}
if (pivot < 0) {
n.reverse
}
else {
val successor = n.lastIndexWhere{_ > n(pivot)}
(n.take(pivot) :+ n(successor)) ++
((n.slice(pivot+1, successor):+ n(pivot)) ++ n.drop(successor+1)).reverse
}
}
Таким образом, вы получите Vector[Int]
, если вы передали один методу, и List[Double]
, если вы передадите его методу. Так что насчет String
с? Это не фактические последовательности, но они могут быть неявно преобразованы в Seq[Char]
. Можно изменить определение этого метода, ожидая некоторый тип, который может быть неявно преобразован в Seq[A]
, но опять же вывод типа не будет работать надежно - или, по крайней мере, я не смог бы заставить его работать надежно. В качестве простого обходного пути вы можете определить дополнительный метод для String
s:
def nextPermutation(s: String): String =
nextPermutation[Char,Seq](s.toSeq).mkString