2016-12-27 4 views
1

У меня есть метод, который делает перестановки:Scala перестановками через flatMap из подмножества

def permutations[T](lst: List[T]): List[List[T]] = lst match { 
    case Nil => List(Nil) 
    case x :: xs => permutations(xs) flatMap { perm => 
     (0 to xs.length) map { num => 
     (perm take num) ++ List(x) ++ (perm drop num) 
     } 
    } 
    } 

Во-первых, принять рекурсивный вызов с парой - голова, хвост для списка («а», «б», «в "): c - Nil b - c a - bc

и переставить до и после деталей. В результате у меня есть все перестановки с трех позже. Мой вопрос следующий: почему рекурсивный вызов не возвращает промежуточный оператор типа «bc», «cb», «c» и возвращает допустимый набор из трех позже.

+1

Я предполагаю, что вы хотите реализовать ваш собственный, но в случае, если вы не знали, что 'Seq' имеет метод' permutations' ('List' реализует' Seq'). – Simon

+0

Я знаю о методе перестановки в Seq, это просто эксперимент с комбинаторикой. – pacman

ответ

2

Ну, в каждой итерации вы обязательно возвращать только списки с теми же размерами, что и входной список, потому что вы возвращаетесь перестановки формы (perm take num) ++ List(x) ++ (perm drop num), которая всегда будет содержать все элементы в perm плюс x элемента.

Следовательно, рекурсивно - если каждый цикл возвращает только значения того же размера, что и его вход (включая конечный регистр Nil), тогда конечный результат должен содержать только перестановки одного размера.

Чтобы это исправить, вы можете добавить permбезx в результате каждого цикла, но вам придется добавить distinct избавиться от дупликации:

def permutations[T](lst: List[T]): List[List[T]] = lst match { 
    case Nil => List(Nil) 
    case x :: xs => permutations(xs) flatMap { perm => 
    ((0 to xs.length) flatMap { num => 
     List(perm, (perm take num) ++ List(x) ++ (perm drop num)) 
    }).distinct 
    } 
} 
+0

Вы сказали, что «на каждой итерации вы обязательно возвращаете только списки с тем же размером, что и входной список», а что касается случая, когда 'perm' содержит только один элемент (например,« c ») в рекурсивном вызове, он должен возвращать« Список » (x) + "c" 'и длина не будет совпадать с длиной списка ввода – pacman

+0

, но' perm' _can't_ содержит только один элемент 'c', потому что это утверждение верно для рекурсивного вызова, создающего' perm'! Подумайте о законах «доказательства по индукции»: если вы докажете требование «основы» (для 'Nil', все результаты имеют размер 0) и« индуктивный шаг »(если мы _assume_' perm.size == xs. size ", то результаты итерации будут иметь тот же размер, что и' lst' - это то, что я показал), тогда - претензия означает ВСЕ Итерации. –

+0

Я не думаю, что 'perm' содержит строчное количество элементов как' lst' на каждой итерации, я добавляю println к 'perm', и это было' Nil' '' c "', '" bc "', ' "Си-Би"'. – pacman

Смежные вопросы