Декартово произведение двух списков

Возможный дубликат:
F# - перекрестное произведение двух списков
Эффективное проектирование списка списков в F#

У меня есть функция, которая принимает два целочисленных списка и возвращает один список со всеми декартовыми произведениями. Я думаю, что у меня есть правильная идея, но не правильная реализация. Могу ли я получить некоторые указатели?

let rec cartesian = function
 | ([],[]) -> []
 | (xs,[]) -> []
 | ([],ys) -> []
 | (x::xs,ys) ->   List.map(fun y -> (x,y)::[]) cartesian (xs,ys) 

1 ответ

Решение

Это быстрое решение:

let rec cartesian = function
 | ([],[]) -> []
 | (xs,[]) -> []
 | ([],ys) -> []
 | (x::xs, ys) -> (List.map(fun y -> x,y) ys) @ (cartesian (xs,ys))

Идея в том, что с каждым элементом x, вы генерируете список [(x, y1); (x, y2); ...; (x, yn)] и объединить эти списки в целом.

В вашей функции первый случай сопоставления с образцом избыточен. И аргументы удобнее быть в карри. Функция может выглядеть так:

let rec cartesian xs ys = 
  match xs, ys with
  | _, [] -> []
  | [], _ -> []
  | x::xs', _ -> (List.map (fun y -> x, y) ys) @ (cartesian xs' ys)

Как только вы поймете идею, вы увидите, что функция высшего порядка List.collect идеально соответствует задаче:

let cartesian xs ys = 
    xs |> List.collect (fun x -> ys |> List.map (fun y -> x, y))
Другие вопросы по тегам