【问题标题】:In Haskell, how can you sort a list of infinite lists of strings?在 Haskell 中,如何对无限的字符串列表进行排序?
【发布时间】:2011-01-24 13:54:56
【问题描述】:

所以基本上,如果我有一个(有限或无限)字符串列表(有限或无限)列表,是否可以先按长度排序列表,然后按字典顺序排序,不包括重复项?示例输入/输出将是:

输入:

[["a", "b",...], ["a", "aa", "aaa"], ["b", "bb", "bbb",...], ...]

输出:

[“a”、“b”、“aa”、“bb”、“aaa”、“bbb”、...]

我知道输入列表不是有效的 haskell 表达式,但假设有这样的输入。我尝试使用合并算法,但它往往会挂在我给它的输入上。有人可以解释并展示一个可以做到这一点的不错的排序功能吗?如果没有这样的功能,你能解释一下原因吗?

如果有人不明白我所说的排序顺序是什么意思,我的意思是最短长度的字符串首先排序,如果一个或多个字符串长度相同,则使用

谢谢!

【问题讨论】:

  • 你能保证输入列表按照你的例子排序吗?

标签: sorting haskell string list infinite


【解决方案1】:

好吧,我将忽略您对无限数据进行排序的请求。

要按子列表的长度排序,然后按字典顺序,我们可以很容易地做到这一点。哦,你想删除重复项。

我们将从一个示例开始:

> s
[["a","b"],["a","aa","aaa"],["b","bb","bbb"]]

然后逐步构建程序。

首先按长度排序(使用 Data.Ord.comparing 构建排序体):

> sortBy (comparing length) s
[["a","b"],["a","aa","aaa"],["b","bb","bbb"]]

好的。这看起来很合理。所以让我们先 concat,然后 sortBy 长度然后 alpha:

> sortBy (comparing length) . nub . concat $ s
["a","b","aa","bb","aaa","bbb"]

如果您的输入已排序。否则,您将需要一个稍微不同的主体来排序。

【讨论】:

    【解决方案2】:
    • 通常不可能对无限列表进行排序。因为最小的项目可能在无限的位置,我们必须在输出之前找到它。

    • Merging 无限排序列表是可能的。

    • 一般来说,合并一个无限的排序列表是不可能的。出于与对它们进行排序相同的原因。

    • 可以合并无限的已排序列表,这些列表按头排序(forall i j. i < j => head (lists !! i) <= head (lists !! j))。

    所以我猜你真正想要的是合并一个有序列表的无限列表。这甚至是一项有意义的任务。甚至还有 some existing code 使用它,在那里为单子列表实现 - 在语法方面有点丑陋等等。所以这是一个普通列表的版本:

    mergeOnSortedHeads :: Ord b => (a -> b) -> [[a]] -> [a]
    mergeOnSortedHeads _ [] = []
    mergeOnSortedHeads f ([]:xs) = mergeOnSortedHeads f xs
    mergeOnSortedHeads f ((x:xs):ys) =
      x : mergeOnSortedHeads f (bury xs ys)
      where
        bury [] ks = ks
        bury js [] = [js]
        bury js ([]:ks) = bury js ks
        bury jj@(j:js) ll@(kk@(k:ks):ls)
          | f j <= f k = jj : ll
          | otherwise = kk : bury jj ls
    
    ghci> take 20 $ mergeOnSortedHeads id $ [[0,4,6], [2,3,9], [3,5..], [8]] ++ map repeat [12..]
    [0,2,3,3,4,5,6,7,8,9,9,11,12,12,12,12,12,12,12,12]
    

    顺便说一句:你需要这个做什么?

    【讨论】:

      【解决方案3】:

      最终,您无法对无限列表进行排序,因为列表尾部的项目可能会一直渗透到结果的前面,因此您无法完成对无限列表的排序,直到您看到最后一项,但你的列表是无限的,所以你永远不会到达那里。

      您甚至可以尝试对无限列表进行排序的唯一方法是限制列表的居民。如果列表项的值来自 well-founded set 并且列表的内容是唯一的,那么您至少可以在返回列表初始元素的元素方面取得一些进展。例如,如果列表是不同的自然数,你可以返回你看到的第一个 0,然后是第一个 1,等等。但是在你看到 2 之前,你无法在结果中取得任何进展,无论列表有多远你去了。最终,如果您曾经跳过集合中的某个元素,因为它在源中不存在,那么您将停止生成新的输出元素,直到您掌握了整个输入。

      你可以对字符串做同样的事情,因为它们是有根据的,但如果你打算返回所有可能的字符串,那甚至是遥不可及的。

      简而言之,如果你需要这个,你就会以错误的方式解决你遇到的问题。这不是您想要使用的任何解决方案的易处理路径。

      正如 yairchu 所指出的,合并有限数量的已排序无限列表可以正常工作。

      【讨论】:

        【解决方案4】:

        能否做到在很大程度上取决于您输入数据的性质。如果您在看到较长的列表时可以“停止查找”特定长度的列表并且每个长度只有有限数量的列表,那么您可以按升序浏览这些长度排序,排序并连接结果。这样的事情应该可以工作:

        listsUptoLength n xss = takeWhile (\xs -> length xs <= n) $ xss 
        listsUptoLength' n [] = []
        listsUptoLength' n (xss:xsss) = case listsUptoLength n xss of
            [] -> []
            xss' -> xss' : listsUptoLength' n xsss
        listsOfLength n xsss = concatMap (\xss -> (filter (\xs -> length xs == n) xss)) (listsUptoLength' n xsss) 
        
        sortInfinite xsss = concatMap (\n -> sort . nub $ (listsOfLength n xsss)) [0..] 
        
        f xs y = [xs ++ replicate n y | n <- [1..]]
        test = [ map (\x -> [x]) ['a'..'e'], f "" 'a', f "" 'b', f "b" 'a', f "a" 'b' ] ++ [f start 'c' | start <- f "" 'a'] 
        

        (这些名字可能会被选为更有启发性:)

        您正在使用正则表达式,所以我认为可以使这样的事情起作用;我再次请求更多背景信息!

        【讨论】:

          【解决方案5】:

          感谢大家的投入,对于迟到的回复深表歉意。原来我只是以错误的方式解决问题。我试图做 Yairchu 展示的事情,但我使用内置函数 length 进行合并,但由于显而易见的原因,长度在无限列表上不起作用。无论如何,我通过排序解决了我的问题,因为我在旅途中创建了列表,而不是最终结果。我想知道还有哪些其他语言提供无限列表?这样一个奇怪但有用的概念。

          【讨论】:

          • 不要忘记将最佳回复标记为答案,方法是单击答案下方的复选框。
          【解决方案6】:

          这是一个让你在线排序的算法:

          它效率不高,但它足够懒惰,可以让你转到不同的排序代,即使你对无限列表进行排序。这是一个不错的噱头,但不是很实用。例如排序无限列表[10,9..]:

          *Main> take 10 $ sortingStream [10,9..] !! 0
          [9,8,7,6,5,4,3,2,1,0]
          *Main> take 10 $ sortingStream [10,9..] !! 1
          [8,7,6,5,4,3,2,1,0,-1]
          *Main> take 10 $ sortingStream [10,9..] !! 2
          [7,6,5,4,3,2,1,0,-1,-2]
          *Main> take 10 $ sortingStream [10,9..] !! 3
          [6,5,4,3,2,1,0,-1,-2,-3]
          *Main> take 10 $ sortingStream [10,9..] !! 4
          [5,4,3,2,1,0,-1,-2,-3,-4]
          *Main> take 10 $ sortingStream [10,9..] !! 1000
          [-991,-992,-993,-994,-995,-996,-997,-998,-999,-1000]
          

          正如您所见,排序每一代都在改进。代码:

          produce :: ([a] -> [a]) -> [a] -> [[a]]
          produce f xs = f xs : (produce f (f xs))
          
          
          sortingStream :: (Ord a) => [a] -> [[a]]
          sortingStream = produce ss
          
          ss :: (Ord a) => [a] -> [a]
          ss [] = []
          ss [x] = [x]
          ss [x,y]    | x <= y = [x,y]
                      | otherwise = [y,x]
          ss (x:y:xs) | x <= y  =  x: (ss (y:xs))
                      | otherwise =  y:(ss (x:xs))
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2010-09-07
            • 1970-01-01
            • 2012-10-04
            • 2018-10-22
            • 1970-01-01
            • 2015-03-26
            相关资源
            最近更新 更多