#f# #combinatorics
#f# #комбинаторика
Вопрос:
Я хочу функцию f
, которая принимает список списков и возвращает список кортежей всех возможных комбинаций, созданных путем взятия одного элемента из каждого списка.
Например
f [["A";"B";"C"];[1;2]]
даст результат:
[("A",1);("A",2);("B",1);("B",2);("C",1);("C",2)]
и:
f [[onions;peas];[mash;fries];[chicken;steak]]
дало бы:
[(onions,mash,chicken);(onions,mash,steak);(onions;fries;chicken) ... (peas,fries,steak)]
Я подумываю о том, чтобы создать свою собственную, но чувствую, что где-то ДОЛЖНА быть библиотечная функция, оптимизированная намного лучше, чем мой подход с большим кулаком, но, похоже, я ничего не могу найти в Google (возможно, я не знаю правильного комбинаторного термина для этого, поэтому продолжайте использовать разные методы и функции комбинации)
Ответ №1:
Как и CaringDev, я не думаю, что существуют какие-либо стандартные библиотечные функции, которые это делают. Я думаю, одна из причин заключается в том, что они будут иметь разные типы.
Код, такой как [["A";"B";"C"];[1;2]]
из OP, даже не компилируется, потому что использование строковых значений указывает компилятору, что это вложенный список строк, но [1;2]
это список целых чисел.
Вместо этого это можно сделать с помощью кортежей, но именно здесь комбинаторная функция для пары будет отличаться от функции для триплета и так далее.
Тем не менее, такие функции тривиальны для реализации:
let combine2 xs ys = [
for x in xs do
for y in ys do
yield x, y ]
let combine3 xs ys zs = [
for x in xs do
for y in ys do
for z in zs do
yield x, y, z ]
Примеры:
> combine2 ["A";"B";"C"] [1;2];;
val it : (string * int) list =
[("A", 1); ("A", 2); ("B", 1); ("B", 2); ("C", 1); ("C", 2)]
> combine3 ["onions"; "peas"] ["mash"; "fries"] ["chicken"; "steak"];;
val it : (string * string * string) list =
[("onions", "mash", "chicken"); ("onions", "mash", "steak");
("onions", "fries", "chicken"); ("onions", "fries", "steak");
("peas", "mash", "chicken"); ("peas", "mash", "steak");
("peas", "fries", "chicken"); ("peas", "fries", "steak")]
Ответ №2:
На самом деле, CaringDev и Mark Seemann не совсем правы. Пока нет реализации библиотеки, но в F # 4.1 будет реализована реализация декартова произведения (скоро появится TM): https://github.com/Microsoft/visualfsharp/pull/989 . Его можно использовать следующим образом:
List.allPairs ["A"; "B"; "C"] [1; 2]
//val it : (string * int) list =
//[("A", 1); ("A", 2); ("B", 1); ("B", 2); ("C", 1); ("C", 2)]
Тем не менее, это не совсем решает вашу проблему, потому что оно принимает только два списка для своих входных данных, но расширение его не должно быть слишком сложным.
Ответ №3:
В стандартных библиотеках F # нет реализации «декартова произведения». Создание собственной реализации (например, с использованием понимания списка) — это прекрасно.