Есть ли библиотечная функция в F # Объединить элементы из разных списков

#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 # нет реализации «декартова произведения». Создание собственной реализации (например, с использованием понимания списка) — это прекрасно.