按照Elm中的第一个索引对元组列表进行排序

时间:2017-04-25 02:14:49

标签: list sorting comparison elm

假设我有一个类似于以下示例的元组列表:

[(5, "a"), (1, "c"), (7, "d")] 

在Elm中,我如何通过第一个元素按升序对列表进行排序,以便得到以下结果?

[(1, "c"), (5, "a"), (7, "d")]

使用Elm List documentationsortBysortWith函数似乎对此案例有用。我对实施的尝试如下:

maxTuples : Tuple(a, b) -> Tuple(a, b) -> Tuple(a, b)
maxTuples t1 t2 = 
    case compare t1 t2 of 
        ((Tuple.first t1) >= (Tuple.first t2)) -> GT
         _                                     -> LT


sortByFirst : List (Tuple (a, b)) -> List (Tuple (a, b))
sortByFirst lst = 
    List.sortWith maxTuples lst

但是,我遇到了以下性质的编译器错误:

I ran into something unexpected when parsing your code!

99|         ((Tuple.first t1) >= (Tuple.first t2)) -> GT
                ^
I am looking for one of the following things:

an upper case name

我的预感是,编译器正在根据GT库的API查找LT / EQ / List,但如果是这样,我不是确定我们如何能够使用sortBysortWith按照每个元素的第一个索引对Elm中的元组列表进行排序。

3 个答案:

答案 0 :(得分:5)

您找到了正确的功能。在您的代码中,实际上存在多个问题:

  1. 类型注释应该只是(a, b),而不是Tuple(a, b)
  2. 您将t1t2进行比较,后者会按字典顺序比较元组。你真的想要compare (Tuple.first t1) (Tuple.first t2)
  3. case分支需要->之前的模式。在这种情况下,类似EQ,因为您匹配compare的结果,返回Order类型。
  4. 你可以修改这样的代码:

    maxTuples : (comparable, b) -> (comparable, b) -> (comparable, b)
    maxTuples t1 t2 = 
        case compare (Tuple.first t1) (Tuple.first t2) of 
            GT -> GT
            EQ -> EQ
             _ -> LT
    

    但是现在有一个不必要的重复,你只是返回compare函数的结果。

    maxTuples t1 t2 = 
        compare (Tuple.first t1) (Tuple.first t2)
    

    与sort函数一起,它看起来像这样:

    sortByFirst lst = 
        List.sortWith (\t1 t2 -> compare (Tuple.first t1) (Tuple.first t2)) lst
    

    事实证明,这种操作很常见,特别是对于记录列表。出于这个原因,Elm提供了另一个功能 - sortBy。它需要一个函数并在应用函数后比较元素:

    sortBy f lst =
        List.sortWith (\a b -> compare (f a) (f b)) lst
    

    因此,您可以使用sortBy函数来大大简化代码:

    sortByFirst : List (comparable, b) -> List (comparable, b)
    sortByFirst =
        sortBy Tuple.first
    

答案 1 :(得分:4)

值得注意的是,你想要的是List.sort的默认行为(sort将使用元组的第一个元素来排序列表,如果两个元素具有相同的第一个元素将移动以比较第二个元素等等) List.sort [(5, "a"), (1, "c"), (1, "a"), (7, "d")] == [(1,"a"),(1,"c"),(5,"a"),(7,"d")]

在这种情况下使用sortBy是多余的。

答案 2 :(得分:0)

我不确定compare中的case compare t1 t2 of是什么,但您可以使用直线if代替case(并且还可以使用解构来代替如果您愿意,可以Tuple.first

maxTuples ( val1, _ ) ( val2, _ ) =
    if val1 >= val2 then
        GT
    else
        LT

我在https://ellie-app.com/ZZ9Hzhg7yva1/2有一个完整的工作示例(还需要进行一些类型注释更改才能进行编译)

但是,sortBy是更简单的选项,因为它可以只需Tuple.first对其中的任何内容进行排序:

sortByFirst lst =
    List.sortBy Tuple.first lst

该版本位于https://ellie-app.com/ZZ9Hzhg7yva1/3