Я решаю проблемы с Scala, сначала решая их в Haskell, а затем переводя.:)
reorderings xs = take len . map (take len) . tails . cycle $ xs
where len = length xs
Это самый простой способ, который я мог придумать, который генерирует список всех возможных сдвигов путем многократного «сдвига влево».
ghci> reorderings [1..5]
[[1,2,3,4,5],[2,3,4,5,1],[3,4,5,1,2],[4,5,1,2,3],[5,1,2,3,4]]
Концепция относительнопросто (для тех, кто знаком с функциональным программированием).Во-первых, cycle
исходный список, создающий бесконечный поток, из которого можно извлечь.Затем разбейте этот поток на поток потоков, где каждый последующий поток отбрасывает первый элемент предыдущего потока (tails
).Затем ограничьте каждый подпоток длиной исходного списка (map (take len)
).Наконец, ограничьте поток потоков длиной исходного списка, так как существует только len
возможных переупорядочений (take len
).
Итак, давайте сделаем это в Scala сейчас.
def reorderings[A](xs: List[A]):List[List[A]] = {
val len = xs.length
Stream.continually(xs).flatten // cycle
.tails
.map(_.take(len).toList)
.take(len)
.toList
}
Нам просто пришлось использовать небольшой обходной путь для cycle
(не уверен, что стандартные библиотеки Scala обеспечивают цикл, хотя я был приятно удивлен, обнаружив, что они предоставляют tails
), и несколько toList
s (списки на Haskell *)1020 * - это ленивые потоки, в то время как Scala - строгие), но в остальном он точно такой же, как Haskell, и, насколько я могу судить, ведет себя точно так же.Вы можете почти думать о .
Скалы как о поведении, похожем на поведение Хаскелла, за исключением того, что он движется в противоположном направлении.
Также обратите внимание, что это почти то же самое, что и решение dhg, за исключением случаев, когда нет обращений, которые (с другой стороны) делаютон более эффективен, но (с другой стороны) обеспечивает циклы в «обратном» порядке, а не «прямом».