F# Сортировка массива кортежей

let standard = (0, 4.5M, 4L)
let tuples = [| ("A", -2, 1.0M, 2L); 
                ("B", -1, 2.0M, 3L); 
                ("C", 0, 3.0M, 4L); 
                ("D", 1, 4.0M, 5L); 
                ("E", 2, 5.0M, 6L) |]
let qualified = tuples
              |> Array.sortBy(fun (_, a, b, c) -> (a, -b, c))
              |> Array.filter(fun (_, a, b, c) -> (a, b, c) <= standard)
printfn "%A" qualified

У меня есть массив кортежей и стандарт. Я хочу отсортировать кортежи и выбрать те кортежи, которые соответствуют требованиям.
Для кортежей я игнорирую первый элемент и сортирую второй элемент и четвертый элемент обычным способом, а также сортирую третий элемент в обратном порядке. ; и у меня есть стандартный кортеж, поскольку все кортежи со вторым элементом не меньше стандартного, а третий элемент не больше стандартного являются квалифицированными кортежами. В приведенном выше примере квалифицированный кортеж имеет вид: = [| ("C", 0, 3.0M, 4L) |] Условия таковы: второй элемент >= 0 и третий элемент ‹= 4.5M и четвертый элемент >= 4L Но мой код НЕ работал! Дайте мне знать, как написать функцию, которая может выполнять эту работу! Спасибо и хороших выходных. Джон


person John John    schedule 04.12.2011    source источник
comment
В чем код не сработал?   -  person Richard    schedule 04.12.2011


Ответы (2)


Я не думаю, что есть какой-то умный способ сделать то, что вам нужно, используя встроенное сравнение, которое работает с кортежами. Основная проблема заключается в том, что при сравнении первый элемент рассматривается как наиболее значимый, поэтому решение принимается только с использованием первых нескольких элементов (даже без учета остальных значений). В ваших условиях указаны ограничения на все элементы. Итак, , решение от Густаво, вероятно, самый простой способ.

Однако есть некоторые незначительные моменты. Во-первых, может быть хорошей идеей выполнить фильтрацию перед сортировкой, потому что тогда вашей функции сортировки потребуется отсортировать меньше элементов:

 let qualified = 
   tuples 
   |> Array.sortBy (...) 
   |> Array.filter (...)

Если вы хотите представить условие в каком-то глобальном значении, которое легко изменить, то создания кортежа с 3 значениями, указывающими требуемый минимум/максимум, недостаточно, потому что вы не говорите, является ли значение минимальным или максимальным. , Однако вы можете использовать кортеж функций, которые задают условия:

let standard = ((fun _ -> true), (<=) 0, (>=) 4.5M, (<=) 4L) 

Это указывает, что все значения первого элемента в порядке, значения второго элемента должны быть больше нуля ( (<=) 0 обозначает функцию, которая принимает x и возвращает 0 <= x) и т. д. Затем вы можете написать:

let conditionsHold (p1, p2, p3, p4) (v1, v2, v3, v4) = 
  p1 v1 && p2 v2 && p3 v3 && p4 v4

let qualified = 
  tuples 
  |> Array.sortBy(fun (_, a, b, c) -> (a, -b, c)) 
  |> Array.filter (conditionsHold standard)
person Tomas Petricek    schedule 04.12.2011
comment
Привет, Томас: Большое спасибо за ваш отличный код и подробные объяснения. В вашем коде также была небольшая проблема, лучше поставить фильтр перед сортировкой! Еще раз спасибо за вашу большую помощь! Джон - person John John; 05.12.2011

Просто измените последнюю строку на:

Array.filter(fun (_, a, b, c) -> let (x,y,z) = standard in a >= x && b <= y && c >= z)

Обратите внимание, что кортеж ("D", 1, 4.0M, 5L) также подходит.

ОБНОВИТЬ:

Томаш прав, лучше сначала отфильтровать. Еще одним интересным функциональным способом ее решения может быть превращение тройки в аппликативный функтор.

let pure' x = (x,x,x)
let (<*>) (f,g,h) (x,y,z) = (f x, g y, h z)

let standard = (0, 4.5M, 4L)
let tuples = [| ("A", -2, 1.0M, 2L); 
                ("B", -1, 2.0M, 3L); 
                ("C", 0, 3.0M, 4L); 
                ("D", 1, 4.0M, 5L); 
                ("E", 2, 5.0M, 6L) |]
let qualified = tuples              
              |> Array.filter(fun (_, a, b, c) -> ((>=),(<=),(>=)) <*> (a,b,c) <*> standard = pure' true)
              |> Array.sortBy(fun (_, a, b, c) -> (a, -b, c))
person Gus    schedule 04.12.2011
comment
Спасибо большое. Однако я думаю по-другому: если я использую отрицательное значение перед третьим элементом для массива кортежей, затем сортирую массив кортежей, а затем просто сравниваю со стандартным кортежем, я могу получить правильные результаты, но я должен сделать некоторые тестирование. Еще раз спасибо за ваш код! - person John John; 04.12.2011
comment
@Gustavo - использование аппликативного функтора - интересная возможность, но я думаю, что это просто делает код слишком сложным без веской причины. Я чувствую, что даже моя версия может быть излишне сложной, но, по крайней мере, вам не нужно вводить причудливые концепции, такие как аппликативные функторы :-). (т.е. я думаю, что F # не должен слепо использовать шаблоны Haskell) - person Tomas Petricek; 04.12.2011
comment
@ Томас, наверное, ты прав. Для этого случая может быть слишком много. Мне лично нравится читабельность аппликативного функтора, и я хотел показать другую альтернативу. - person Gus; 04.12.2011