Декартова половина квадрата списка
Вопрос о том, как сгенерировать декартово произведение списка с самим собой в 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)]