【问题标题】:Lexicographically sort a list of Strings without regard for case - Haskell按字典顺序对字符串列表进行排序而不考虑大小写 - Haskell
【发布时间】:2021-06-02 17:09:23
【问题描述】:

我已经尝试对这个字符串列表进行排序十个小时了。这十个小时主要用于充实解决方法,但命运是残酷的,经过所有这些努力,我的解决方法仍然需要我对字符串列表进行排序而不考虑大小写。

我希望这个函数做的一个例子:

 Input: ["In", "Thats", "pLAIN"]
 Output: ["In", "pLAIN", "Thats"]

基本上我想对字符串进行排序,就好像它们都是小写一样,但保持输入的大小写

到目前为止我的代码:

--This function inserts the strings with capitals in them into the list of lower case only strings
--alphabetically
insertCapitals :: [String] -> [String] -> [String]
insertCapitals capitalList lowerList
--Base case
 |capitalList == [] && lowerList == [] = []
--If the capital list is empty then append the rest of the lowerList
 |capitalList == [] = (lowerListHead:insertCapitals capitalList tailedLowerList)
--If the lowerList is empty append the rest of the capitalList
 |lowerList == [] = (capitalListHead:insertCapitals tailedCapitalList lowerList)
--If the current lowercase word is less than the current uppercase word then append the lowercase word
 |compareResult == LT = (lowerListHead:insertCapitals capitalList tailedLowerList)
--If the current uppercase word is less than the current lowercase word then append the uppercase word
 |compareResult == GT = (capitalListHead:insertCapitals tailedCapitalList lowerList)

此代码是我的变通方法尝试的一部分。它通过获取原始列表来工作,将其分解为完全小写字符串的列表和剩余的任何字符串的列表(所有这些都将具有大写字母)。我的代码的问题是它要求小写字符串列表和所有其他字符串列表都按字母顺序排列,而不考虑大小写。

基本上我的问题来了一个完整的循环。

提前感谢您的帮助

【问题讨论】:

    标签: string list sorting haskell


    【解决方案1】:

    基本上我想对字符串进行排序,就好像它们都是小写一样,但保持输入的大小写

    有一个巧妙的技巧:将每个实际值与要排序的值配对。然后,您执行排序,使用排序依据值进行比较。最后,一旦对列表进行排序,您就可以删除排序依据数据。

    在您的情况下,您可以先将列表中的每个 String 与其自身的小写版本配对。

    import Data.Char (toLower)
    
    lexSort :: [String] -> [String]
    lexSort xs = ... $ zip (fmap toLower <$> xs) xs
    

    根据您的示例,如果您的输入是 ["In", "Thats", "pLAIN"],那么您现在有一个类似于 [("in","In"),("thats","Thats"),("plain","pLAIN")] 的列表。下一步是什么?进行排序:

    import Data.Char (toLower)
    import Data.List (sort)
    
    lexSort :: [String] -> [String]
    lexSort xs = ... $ sort $ zip (fmap toLower <$> xs) xs
    

    pair 的Ord 实例将首先通过pair 的第一个元素进行比较,只有当它们相等时才会查看第二个元素。这在您的情况下是完美的,因为第一个元素是小写值,这是您想要排序的值。所以,此时,您将拥有[("in","In"),("plain","pLAIN"),("thats","Thats")]

    当然,如果这是一个不允许你使用内置排序的作业,你将不得不自己编写这部分,但至少你不必再担心大小写了。

    最后,只需去掉小写的东西,结果就是你想要的。再来一个fmap

    lexSort xs = fmap snd $ sort $ zip (fmap toLower <$> xs) xs
    

    【讨论】:

      【解决方案2】:

      你可以这样做

      sortBy (comparing (map toLower))
      

      或同等地,更快更短

      sortOn (map toLower)
      

      正如它所说的那样,“通过比较字符串的小写版本进行排序”。

      在此处查看文档:https://hackage.haskell.org/package/base-4.14.1.0/docs/Data-List.html#v:sortOn

      【讨论】:

      • 您提供的第二个示例最终最方便地解决了我的问题。感谢您的帮助!
      • 请注意,sortOn 在这方面可能比sortBy 具有更好的性能,因为它使用Schwartzian transform 来避免每次将元素与另一个元素进行比较时从头开始重新评估toLower .我对一些样本数据的测试表明它快了大约 30%。
      猜你喜欢
      • 2021-10-20
      • 1970-01-01
      • 2016-06-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-01-21
      • 2017-02-23
      • 2014-02-08
      相关资源
      最近更新 更多