【问题标题】:F# Sort array of tuplesF#对元组数组进行排序
【发布时间】:2011-12-04 16:55:15
【问题描述】:
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 第三个元素= 4L 但是我的代码不起作用! 让我知道如何编写一个函数可以完成这项工作! 谢谢,周末愉快。 约翰

【问题讨论】:

  • 代码以什么方式“不起作用”?

标签: f# functor applicative


【解决方案1】:

我认为没有任何聪明的方法可以使用适用于元组的内置比较来完成您需要的工作。主要问题是比较将第一个元素视为最重要的元素,因此它决定仅使用前几个元素(甚至不考虑其余值。您的条件指定了对 all 元素的限制。所以,Gustavo 的解决方案可能是最简单的方法。

但是,有一些小问题 - 首先,在 排序 之前执行 过滤 可能是个好主意,因为这样您的排序功能将需要对更少的元素进行排序:

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

如果您想用某个易于更改的全局值来表示条件,那么创建一个包含 3 个值的元组来指定所需的最小值/最大值是不够的,因为您没有说明该值是最小值还是最大值...但是,您可以使用指定条件的函数元组:

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

这指定第一个元素的所有值都可以,第二个元素的值应该大于零((&lt;=) 0 代表一个接受x 并返回0 &lt;= 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)

【讨论】:

  • 您好,Tomas:非常感谢您提供的出色代码和详细解释。您的代码中还有一个小问题,最好在排序之前放置过滤器!再次感谢您的大力帮助!约翰
【解决方案2】:

只需将最后一行更改为:

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

请注意,元组 ("D", 1, 4.0M, 5L) 也符合条件。

更新:

Tomas 是对的,最好先过滤。 另一种有趣的函数式解决方法可能是使 3-uple 成为应用函子。

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))

【讨论】:

  • 非常感谢。但是,我在想另一种方式:如果我在元组数组的第三个元素之前使用 put 负数,然后对元组数组进行排序,然后简单地与标准元组进行比较,我可能会得到正确的结果,但我必须做一些测试。再次感谢您的代码!
  • @Gustavo - 使用应用函子是一种有趣的可能性,但我认为它只是让代码过于复杂,没有充分的理由。我觉得即使是我的版本也可能过于复杂,但至少你不需要引入像应用函子这样的花哨概念:-)。 (即我认为 F# 不应该盲目地采用 Haskell 模式)
  • @Tomas - 你可能是对的。对于这种情况可能太多了。我个人喜欢 applicative functor 的可读性,并希望展示另一种选择。
猜你喜欢
  • 1970-01-01
  • 2014-08-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-18
  • 1970-01-01
相关资源
最近更新 更多