Мне предоставили головоломку в подарок. Он состоит из 4 кубов, расположенных бок о бок. Лица каждого куба - один из четырех цветов.Как вычислить декартово произведение n последовательностей в F #?
Для решения головоломки кубы должны быть ориентированы так, чтобы все четыре кубика были разными, все их фронты различны, все их спины различны, а все их дно разные. Левая и правая стороны не имеют значения.
Мое решение псевдо-код был:
- Создать представление каждого куба.
- Получите все возможные ориентации каждого куба (для каждого из них 24).
- Получите все возможные комбинации ориентации каждого куба.
- Найдите комбинацию ориентации , которая удовлетворяет решению.
Я решил загадку, используя реализацию этого псевдо-кода в F #, но я не satisifed с тем, как я сделал шаг 3:
let problemSpace =
seq { for c1 in cube1Orientations do
for c2 in cube2Orientations do
for c3 in cube3Orientations do
for c4 in cube4Orientations do
yield [c1; c2; c3; c4] }
Приведенный выше код очень конкретные, и работает только из декартова произведения четырех последовательностей ориентации. Я начал думать о способе написать его для n последовательностей ориентации.
я придумал (весь код теперь должен выполнить штраф в F # интерактивного):
// Used to just print the contents of a list.
let print =
Seq.fold (fun s i -> s + i.ToString()) "" >> printfn "%s"
// Computes the product of two sequences - kind of; the 2nd argument is weird.
let product (seq1:'a seq) (seq2:'a seq seq) =
seq { for item1 in seq1 do
for item2 in seq2 do
yield item1 |> Seq.singleton |> Seq.append item2 }
Функция продукт может быть использован как так ...
seq { yield Seq.empty }
|> product [ 'a'; 'b'; 'c' ]
|> product [ 'd'; 'e'; 'f' ]
|> product [ 'h'; 'i'; 'j' ]
|> Seq.iter print
.. , которые приводят к ...
let productn (s:seq<#seq<'a>>) =
s |> Seq.fold (fun r s -> r |> product s) (seq { yield Seq.empty })
[ [ 'a'; 'b'; 'c' ]
[ 'd'; 'e'; 'f' ]
[ 'h'; 'i'; 'j' ] ]
|> productn
|> Seq.iter print
Это именно то, что я хочу. productn имеет именно подпись, которую я хочу и работает.
Однако, используя продукт включает в себя противную линии SEQ {выхода Seq.empty}, и он принимает unintuitively:
- последовательности значений (SEQ < «в >)
- Последовательности последовательностей значений (далее < < «Seq в > >)
Второй аргумент не кажется, с дый правильный.
Этот странный интерфейс хорошо спрятан с помощью productn, но по-прежнему воняет мне независимо.
Есть ли более удобные, более интуитивные способы общего вычисления декартова произведения n последовательностей? Есть ли встроенные функции (или комбинация), которые это делают?
+1 - Я думаю, что это в значительной степени отражает суть того, что я пытаюсь сделать. Я предполагаю, что единственным недостатком является зависимость от списков, тогда как моя ужасная версия работает с seqs. –
@Alex Humphrey: Этот алгоритм можно переписать для работы с seq-of-seqs напрямую, но производительность будет сосать. При написании рекурсивных алгоритмов, подобных этому, работа со списками приходит естественным образом из-за естественной что-то: оставшейся структуры. Вы можете легко преобразовать свой вход: допустим, ваши последовательности последовательности последовательностей называются 'ss', а затем вызовите' cart1 [для s в ss -> Seq.toList s] '. – cfern
Что делать, если seq супер-массивный (представьте, что у меня было еще 10 фигур, каждая из которых имела 1000 ориентаций, и я вычислил ориентации с использованием выражений последовательности). Не будет ли использование списков в конечном итоге стать запретительным из-за использования памяти, или я не понимаю? –