【问题标题】:Compute min and max of a tuple list in F#在 F# 中计算元组列表的最小值和最大值
【发布时间】:2012-11-13 19:39:56
【问题描述】:

在 F# 中,给定 game: (int*int) list 我想计算每个元组维度的 minx、maxx、miny、maxy 的最小值和最大值。

这段代码有效,但看起来有点笨拙:

let minX (game: (int*int) list) =  game |> List.map (fun (x,y) -> x) |> Seq.min 
let maxX (game: (int*int) list) =  game |> List.map (fun (x,y) -> x) |> Seq.max 
let minY (game: (int*int) list) =  game |> List.map (fun (x,y) -> y) |> Seq.min 
let maxY (game: (int*int) list) =  game |> List.map (fun (x,y) -> y) |> Seq.max 

有什么改进的提示吗?

【问题讨论】:

    标签: f#


    【解决方案1】:
    let minX game = List.minBy fst game |> fst
    let maxX game = List.maxBy fst game |> fst
    let minY game = List.minBy snd game |> snd
    let maxY game = List.maxBy snd game |> snd
    

    【讨论】:

    • 这些函数当然适用于任何类似的类型,不仅仅是int。只需删除类型规范,瞧!
    • 感谢 pad 的输入。有什么想法可以减少迭代次数吗?
    • @sthiers :如果您只想遍历列表一次,请使用折叠。
    • @sthiers:我赞同 ildjarn 的建议。但是,它看起来并不像您喜欢的那样漂亮。
    • @RamonSnir:我按照你的建议删除了类型注释。
    【解决方案2】:

    和约翰的一样,但更容易阅读:

    let game = [(1,4);(2,1)]
    let minx, miny, maxx, maxy =
        let folder (mx,my,Mx,My) (ax,ay) = min mx ax, min my ay, max Mx ax, max My ay
        ((Int32.MaxValue, Int32.MaxValue, Int32.MinValue, Int32.MinValue), game) ||> List.fold folder
    

    【讨论】:

    • 您可以通过使用List.reduce 而不是List.fold 来进一步简化此操作;这还具有使代码完全通用的额外好处,因为您不需要提供起始状态值。
    • @JackP。如果不遍历列表两次,您如何做到这一点?
    • @JackP。 List.reduce 假设列表中有元素,这有时会很危险。
    • @RobertJeppesen 我的错,我刚醒来就看到了问题——你需要在这里使用List.fold
    • @RamonSnir 是的,但List.fold 返回空列表的输入状态,这也不一定正确。最安全的做法是“手动”检查空列表并以任何对您的应用有意义的方式处理它;在这种情况下,您不妨使用List.reduce
    【解决方案3】:

    您可以进行一些小的更改来改进您所拥有的:

    1. 使用Seq.map 而不是List.map 以避免创建新列表,从而保持内存使用量不变
    2. 使用内置的 fst/snd 函数代替 lambdas
    3. 因为game 是唯一可以使用函数组合使代码更简洁的参数

    你最终得到:

    let minX = Seq.map fst >> Seq.min
    let maxX = Seq.map fst >> Seq.max
    let minY = Seq.map snd >> Seq.min
    let maxY = Seq.map snd >> Seq.max
    

    有趣的是,我发现这比 pad 的解决方案要快很多:10M 元素为 0.28 秒 vs 1.75 秒。

    【讨论】:

    • 或者如果它在一个模块中,这是一个非常合理的情况(甚至,合理的情况)。
    • 如果是这种情况,修复是微不足道的。只要在同一个文件中调用这些函数,它们即使在一个模块中也可以工作。
    • 但这会强制类型为非泛型。
    • OP 正在处理具体类型;他没有要求通用的解决方案。
    • 我仔细记下了正确。罗伯特为空列表返回maxX=Int32.MinValue?易于修复,但按原样损坏。
    【解决方案4】:

    pad的答案折叠版(只有1个列表遍历)

    let minx,miny,maxx,maxy =game |> List.fold (fun (mx,my,Mx,My) (ax,ay) -> 
        let nmx,nMx = if ax<mx then ax,Mx else if ax > Mx then mx,ax else mx,Mx
        let nmy,nMy = if ay<my then ay,My else if ay > My then my,ay else my,My
        nmx,nmy,nMx,nMy) (Int32.MaxValue,Int32.MaxValue,Int32.MinValue,Int32.MinValue)
    

    【讨论】:

      猜你喜欢
      • 2014-09-27
      • 1970-01-01
      • 2016-06-03
      • 2023-04-07
      • 1970-01-01
      • 1970-01-01
      • 2020-12-23
      • 1970-01-01
      • 2015-10-29
      相关资源
      最近更新 更多