Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell计算满足查询的列表的元素_Haskell_Csv_Count - Fatal编程技术网

Haskell计算满足查询的列表的元素

Haskell计算满足查询的列表的元素,haskell,csv,count,Haskell,Csv,Count,我目前正在处理CSV文件,将其解析为[[String]] 该数组中的第一个[字符串]是头文件,例如: ["Code","Address","Town"] 其余的是信息数组 ["ABA","12,east road", "London"] 我想创建一个查询系统,输入和结果如下 >count "Town"="*London*" @1="A*" 14 rows 列名可以作为字符串或带有列索引的@输入 我有一个大小写开关来识别第一个单词输入,因为我要扩展我的CSV阅读器来实现不同的功能。 当

我目前正在处理CSV文件,将其解析为[[String]] 该数组中的第一个[字符串]是头文件,例如:

["Code","Address","Town"]
其余的是信息数组

["ABA","12,east road", "London"]
我想创建一个查询系统,输入和结果如下

>count "Town"="*London*" @1="A*"
14 rows
列名可以作为字符串或带有列索引的@输入 我有一个大小写开关来识别第一个单词输入,因为我要扩展我的CSV阅读器来实现不同的功能。 当它看到单词计数时,它将转到一个函数,该函数将返回行数。我不知道如何开始解析查询。 起初,我认为我可能会在单词计数后将结果字符串拆分为一个字符串列表,在每个查询中执行一个,然后使用满足此查询的列表再次检查下一个查询,留下一个满足所有查询的列表,然后计算条目的数量并返回它们。还有一个case开关可以识别第一个输入是字符串还是@符号。 *用于表示零或单词后面的任何字符。
我不知道如何开始实施,或者如果我错过了一个问题,我可能会遇到我的解决方案。如果有人能帮我起步,我会非常乐意。我对Haskell不是很在行(因为我才刚刚开始),所以我也希望保持它的简单。谢谢你

我对Haskell也不是很精通……但我会这样做:你想要的基本上是:

f $ filter g list
其中“f”可以是类似“count”的东西(实际上是长度),“g”是与查询对应的过滤函数。首先,您可以将输入分为“head”和“tail”(即列表);然后可以使用Parsec来解析查询。您的parsec解析器将只返回一个元组;第一个是函数“f”(如果遇到“count”,则可能是“length”);第二个简单地返回true/false;您将拥有以下类型:

f :: [String] -> Int
g :: [String] -> Bool 

构建“f”和“g”非常容易。我想,如果你在链接页面上稍加研究一下示例,你会自己找到答案。

这里有一种可能的方法

首先,让我们稍微远离字符串表示列表,将记录表示为键/值对,这样数据库就是一个记录列表:

type Field  = (String, String) -- key, value                                    
type Record = [Field]
type Db     = [Record]
在您的表示中读取CSV数据将变成:

type Csv = [[String]]

fromCsv :: Csv -> Db
fromCsv []         = []
fromCsv (ks : vss) = map (zip ks) vss
现在,让我们谈谈查询。在您的设置中,查询本质上是一个筛选器列表,其中每个筛选器标识一个字段并匹配一组值:

type Query  = [Filter]
type Filter = (Selector, ValueFilter)
通过名称或基于一的(!)索引选择字段:

通过应用一系列简单解析器来匹配值,其中解析器要么识别单个字符,要么识别零个或多个任意字符的序列:

type ValueFilter = [Parser]
data Parser      = Char Char | Wildcard
可以使用成功列表方法实现解析,其中每个成功表示剩余的输入,即解析器未使用的输入部分。剩余输入的空列表表示失败。(因此,请注意以下情况下产生的结果中
[[]]
[[[]]]
之间的差异。)

然后过滤值发展为回溯:

filterValue :: ValueFilter -> String -> Bool
filterValue ps cs = any null (go ps cs)
  where
    go [] cs       = [cs]
    go (p : ps) cs = concatMap (go ps) (parse p cs)
值选择非常简单:

select :: Selector -> Record -> Maybe String
select (FieldName s) r                           = lookup s r
select (FieldIndex n) r | n > 0 && n <= length r = Just (snd (r !! (n - 1)))
                        | otherwise              = Nothing
最后,为了执行一个完整的查询,我们有

exec :: Query -> Db -> [Record]
exec = (flip . foldl . flip) (filter . apply)
(我将查询本身的解析留作练习:

readQuery :: String -> Maybe Query
readQuery = ...
但我建议使用解析器组合器库,如或。)

现在,让我们测试一下。首先,我们介绍一个CSV格式的小型数据库:

csv :: Csv
csv =
  [ ["Name" , "City"      ]
     -------  ------------                                                      
  , ["Will" , "London"    ]
  , ["John" , "London"    ]
  , ["Chris", "Manchester"]
  , ["Colin", "Liverpool" ]
  , ["Nick" , "London"    ]
  ]
然后,我们构造一个简单的查询:

-- "Name"="*i*" @2="London"                                                     
query :: Query
query =
  [ (FieldName "Name", [Wildcard, Char 'i', Wildcard])
  , (FieldIndex 2,
      [Char 'L', Char 'o', Char 'n', Char 'd', Char 'o', Char 'n'])
  ]
事实上,对数据库运行我们的查询会产生:

> exec query (fromCsv csv)
[[("Name","Will"),("City","London")],[("Name","Nick"),("City","London")]]
或者,如果您只是在计算查询结果之后:

> length $ exec query (fromCsv csv)
2

当然,这只是一种方法,可以肯定的是,我们可以想出许多替代方法。如上所述,将问题分解为小函数的一个很好的方面是,您可以轻松地单独测试和实验解决方案的小部分。

您想在haskell中创建一种“微语言”吗?还是要分析整个字符串?也就是说,“>”是ghci提示符还是应用程序的提示符?我输入了>以区分控制台输入和输出:)我有一个运行的主程序,这就像一个命令窗口,我可以加载一个csv文件,解析它,保存它,等等。我想在csv文件上创建一个SQL查询系统,以供练习。感谢您在回答中付出的努力,非常感谢。我在CSV文件解析方面有一个巨大的项目要做,我觉得我没有资格自己做这件事,因为我在大学模块中学习haskell不到3个月。对于这个项目,除了互联网,我不能得到任何外界的帮助。我整天都在看你的代码,甚至有些事情我也不懂。但是谢谢你
-- "Name"="*i*" @2="London"                                                     
query :: Query
query =
  [ (FieldName "Name", [Wildcard, Char 'i', Wildcard])
  , (FieldIndex 2,
      [Char 'L', Char 'o', Char 'n', Char 'd', Char 'o', Char 'n'])
  ]
> exec query (fromCsv csv)
[[("Name","Will"),("City","London")],[("Name","Nick"),("City","London")]]
> length $ exec query (fromCsv csv)
2