F# 检查列表是否已排序的函数

发布于 2024-09-18 10:05:11 字数 412 浏览 14 评论 0原文

我必须编写一个函数,如果给定列表按升序排序,则该函数返回 true。空列表和 1 元素列表已排序。另外,[5,12,12] 应该返回 true。

我写了一个似乎可以工作的函数:

let rec isSorted (l: int list) = 
    match l with
    | [] -> true
    | [x] -> true
    | [x;y] -> x <= y
    | x::y::xr -> if x > y then false else isSorted([y] @ xr);

但它似乎有点不对劲......我想一定有一种更简单的方法来做到这一点?我讨厌我必须匹配 4 个案例,但我不知道如何让它变得更聪明。

还有更好的解决方案吗?

I have to write a function, that returns true if a given list is sorted in ascending order. The empty and 1-element lists are sorted. Also, [5,12,12] should return true.

I've written a function that seems to work:

let rec isSorted (l: int list) = 
    match l with
    | [] -> true
    | [x] -> true
    | [x;y] -> x <= y
    | x::y::xr -> if x > y then false else isSorted([y] @ xr);

But it seems a bit off... I'm thinking there must be an easier way to do this? I hate that I have to match 4 cases, but I cant figure out how to make it any smarter.

Any better solutions?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

残龙傲雪 2024-09-25 10:05:11

您可以组合现有功能:

let isAscending l = l |> Seq.pairwise |> Seq.forall (fun (a, b) -> a <= b)

printfn "%b" (isAscending []) // true
printfn "%b" (isAscending [1]) // true
printfn "%b" (isAscending [5;12]) // true
printfn "%b" (isAscending [5;12;12]) // true
printfn "%b" (isAscending [5;12;12;11]) // false

you can combine existing functions:

let isAscending l = l |> Seq.pairwise |> Seq.forall (fun (a, b) -> a <= b)

printfn "%b" (isAscending []) // true
printfn "%b" (isAscending [1]) // true
printfn "%b" (isAscending [5;12]) // true
printfn "%b" (isAscending [5;12;12]) // true
printfn "%b" (isAscending [5;12;12;11]) // false
深海少女心 2024-09-25 10:05:11

好吧,永远不要说

[y] @ xr

什么时候

y :: xr

会好。 (一般来说,@ 是一种代码味道。)

有点挑剔,但最后一行可以

| x::((y::_)as t) -> if x > y then false else isSorted(t)

使您免于进行任何分配。

现在,您需要第三个案例吗?如果删除它会发生什么?

Well, never say

[y] @ xr

when

y :: xr

will do just as well. (In general, @ is a code smell.)

Kinda nitpicky, but the last line could be

| x::((y::_)as t) -> if x > y then false else isSorted(t)

and save you from doing any allocation.

Now, do you need the third case? What happens if you remove it?

舂唻埖巳落 2024-09-25 10:05:11

回到原始代码(而不是建议的库调用),我想说您可以进行一些改进:

  • 第三个匹配情况并不是真正需要的(已经提到过)。
  • 在第二种情况下,您不想为该值指定名称,因此您不会访问它。
  • 在第四种情况下,将 y::xr 拆开只是用 [y] @ xr (或 y ::xr)。 as 表达式看起来更好。
  • 您只是组合了两个逻辑结果,if..then 看起来有点不合适。

我提出了以下修订版本:

let rec isSorted l =
    match l with
    | [] | [_] -> true
    | h1::(h2::_ as tail) -> h1 <= h2 && isSorted tail

我怀疑它比原始版本更有效,但它更美观。

Getting back to the original code (as opposed to the suggested library calls), I'd say you can make a few improvements:

  • The third match case isn't really needed (was already mentioned).
  • In the second case you don't want to give the value a name, you're not accessing it.
  • In the forth case, it doesn't look right to take apart y::xr just to stitch it together again with [y] @ xr (or y::xr). An as expression seems nicer.
  • You are just combining two logical results, the if..then looks a bit out of place.

I have come up with the following revised version:

let rec isSorted l =
    match l with
    | [] | [_] -> true
    | h1::(h2::_ as tail) -> h1 <= h2 && isSorted tail

I doubt it's more efficient than the original, but it's easier on the eye.

往日 2024-09-25 10:05:11

就效率而言,这是一个特别糟糕的解决方案,因此我永远不会在现实世界中使用它,但这里有一个漂亮的函数式方法来查看我在博客示例中提出的问题:

let isSorted l = l = (l|>List.sort)

This is a particularly bad solution in terms of efficiency, so I'd never use this in the real world, but here is a nifty functional way of looking at the problem that I came up with as part of a blog example:

let isSorted l = l = (l|>List.sort)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文