Декартова половина квадрата списка

Вопрос о том, как сгенерировать декартово произведение списка с самим собой в F#, знаком, но мне нужно что-то немного другое: половина полученного квадрата. То есть [1; 2; 3] -> [(1, 2), (1, 3), (2, 3)].

Наиболее очевидные способы сделать это включают в себя вложенные циклы с целочисленными индексами, но какой самый идиоматичный способ сделать это в F#? Я не беспокоюсь о производительности, просто простота и элегантность.

2 ответа

Решение

Я не уверен, но я думаю, что вы хотите что-то вроде этого:

let pairs = function
   | [] -> [] 
   | (x::xs) -> List.map (fun x' -> (x,x')) xs

let rec hSquare xs =                        
   match xs with                           
   | [] -> []                              
   | (_::ys) -> pairs xs @ hSquare ys

с hSquare вы получаете например:

> hSquare [1..3];;
val it : (int * int) list = [(1, 2); (1, 3); (2, 3)]
> hSquare [1..4];;
val it : (int * int) list = [(1, 2); (1, 3); (1, 4); (2, 3); (2, 4); (3, 4)]

который включает в себя ваш пример

замечания

  • Это, конечно, не какая-то половина обычного декартова произведения (это было бы [(1,1);(1,2);(1,3);(2,1);(2,2);(2,3);(3,1);(3,2);(3,3)] в твоем случае
  • Я не заботился о производительности, обзвонах, что бы здесь ни было - вы, безусловно, можете улучшить это.
  • Я просто хотел знать, если вы ищете это, и это слишком для комментария.

Вот обязательная альтернатива, основанная на предварительном ответе Карстена Кенига: для достижения этих результатов можно также использовать выражение последовательности.

let c2 args = seq{
    let argsi = Seq.mapi (fun i x -> i, x) args 
    for (i, x) in argsi do
        for (j, y) in argsi do
            if i < j then yield (x, y) }

c2 [1..3]   // val it : seq<int * int> = seq [(1, 2); (1, 3); (2, 3)]
Другие вопросы по тегам