【问题标题】:Haskell: readfile line by line and put into listHaskell:逐行读取文件并放入列表
【发布时间】:2014-03-20 23:40:54
【问题描述】:

我正在尝试将文件名放入我的程序中,然后将文件逐行读取到字符串列表中。我希望在进入程序的其余部分之前读取整个文件。我要阅读的文件也大约有 10K 行。我还需要检查每一行的长度,以便能够将它们放入不同的列表中。我目前有:

stageone :: String->[[String]]
stageone xs = do
        fileLines <-readFile.xs
        let line = lines fileLines
        xss -- dont know where to go from here

【问题讨论】:

  • 在继续之前需要阅读所有文件的原因是什么?这是教授的要求吗?你关心性能吗?特别是因为你有一个 10K 的文件,我认为这就是 Haskell 惰性 IO 的好处。
  • 我在工作时需要搜索整个文件,所以我想先阅读整个文件。
  • 但是 8,002 元素的存在会影响您找到第三个元素吗? findElement xs = filter (\x -&gt; x &gt; 5 &amp;&amp; isOdd x) xs 该列表可能是无限的,但 filter 可以立即开始返回结果。
  • 好吧,我的计划是最终将每个字符串长度分解为自己的列表,这样当我需要搜索时,我可以获取搜索键长度,然后只搜索包含长度元素的列表。因此,如果我的键长度为 5,我将只搜索具有长度为 5 的元素的列表。
  • 这可能不会以最适合 Haskell 的方法结束。我很难根据我所知道的来判断。它可以很容易地将您的搜索应用于长度过滤器的结果。也可能更有效率。懒惰做有趣的事情。从 C 或 Java 中摆脱直接的严格评估思维是学习 Haskell 中最困难的部分之一。

标签: haskell readfile nested-lists


【解决方案1】:

一个简单的严格读取文件的方法是使用Text,默认情况下有一个严格的readFile

import qualified Data.Text    as Text
import qualified Data.Text.IO as Text

main = do
    ls <- fmap Text.lines (Text.readFile "filename.txt")
    ... -- The world is your oyster!

到程序的第二行,整个文件已经被处理了。

学习使用Text 而不是String 是一个好习惯,因为Text 效率更高。要了解有关text 库的更多信息,您可以开始here

【讨论】:

  • 我会使用文本,但我需要能够在数据包含在内之后搜索列表,并且我将使用字符串进行搜索。我可以用字符串做同样的事情吗?
  • @tucker19 是的,当然! strict package 的严格版本是 readFile here
【解决方案2】:

欢迎来到 Haskell。不幸的是,您的函数的类型签名不起作用。你不能离开这里的 IO monad。

stageone :: String -> IO [[String]]

是你最终会得到的。

您要做的是将您的需求分解为功能并实现每个功能。这些函数也许可以是没有 IO 的纯函数。然后回来把它们放在一起。这就是 Haskell 代码的开发方式。注意类型签名。如果你被难住了,试着只写签名并从那里开始工作。

如何确定一条线的长度?

如何将函数应用于列表中的每个项目并保留结果?

如何从文件中读取一行?

一旦你有 10K 行长度,然后呢?把它们写出来?打印出来?

一旦您制定了计划,您就可以在ghci 中编写和测试这些较小的部分。

祝你好运。

【讨论】:

  • 我很笨,我应该有 IO,我知道。我知道该怎么做,我只是在逐行读取文件时遇到问题。
  • 不,我们都在学习时这样做。 “我如何摆脱 IO monad”是 Haskell 中最大的常见问题之一。
  • 我们先把巨大的文件读入一个列表,然后我可以把它分解成更小的列表
  • 这很可能是正确的方法。
【解决方案3】:

好的,这里是函数的所有无点单行荣耀(或丑陋),看不到任何 lambda...

module Main where

import Data.List ( sortBy, groupBy )
import Data.Function ( on )
import Data.Ord ( comparing )
import Control.Arrow ( (&&&) )

stageone :: String -> IO [[String]]
stageone = fmap (map (map snd) . groupBy ((==) `on` fst) . sortBy (comparing fst) . map (length &&& id) . lines) . readFile

让我们分解一下。顶层是readFilefmap 的组合。我们总是从右到左阅读函数组合。 stageone 的无点参数传递给 readFile,它返回一个 IO Stringfmap 将其函数参数发送到其中,以在 String 糖果壳内转换 String

这个函数是我们从右到左阅读的另一个组合。首先,我们将lines 应用于String 以将其分解为行列表。然后我们在行列表上map(length &amp;&amp;&amp; id),它将每行转换为由行的长度和行本身组成的对。接下来,我们通过比较每个对的第一个元素(长度)来对列表进行排序。排序是稳定的,因此在相同长度的行中,行将保持其原始顺序。接下来,我们应用groupBy((==) `on` fst),它将具有相同第一个元素(长度)的对的运行分组到它们自己的子列表中。最后,我们将map (map snd) 应用于对列表的列表。外部map 遍历组,内部map 遍历组内的对列表,将每对替换为其第二个元素(行)。

呼!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-09
    • 2011-03-17
    相关资源
    最近更新 更多