通过索引列表从列表中获取元素

时间:2015-12-27 04:15:21

标签: list haskell

我在Haskell中有两个列表。

包含字符串值的原始列表:

["Hello", "HELLO", "", "WORLD", "xxx", "world"]

包含整数值的索引列表,其中字符串在原始列表中都是大写:

[1,3]

我使用我创建的函数增加了索引列表中的所有值,并生成index2列表,整体看起来像这样:

我的代码:

import Data.List 
import Data.Char 
import Data.Maybe 

main = do 
    contents <- readFile "h.txt" 
    let original = lines (contents) 
    let allUpper = lines (map toUpper contents) 
    let onlyUpper = filter(/="") (intersect original allUpper) 
    let upperIndex = findIndices ('elem' onlyUpper) original 
    let index2 = (map increment upperIndex) 
    print index2 

increment :: Int -> Int 
increment x = x+1 

在你的帮助下,我成功地走到了这一步。但是,由于我是初学者,我似乎不明白迭代如何工作。

我想要完成的是检查原始列表中相应的索引值(index2)是否为空,如果它们为空,我想在index2中删除它们

2 个答案:

答案 0 :(得分:2)

过滤空元素

  

我想要完成的事情是检查是否相应   索引值(在index2中)在原始列表中是空的,如果是   它们是空的,我想在index2中删除它们。

代码已过滤掉空元素!请看以下行:

let onlyUpper = filter(/="") (intersect original allUpper)

这一行做了两件事:

  • 它仅保留仅使用大写字母(intersect original allUpper),
  • 构成的元素
  • 它过滤掉空元素(filter(/=""))。

如果空元素是指仅包含空格字符或没有空格的字符串,则可以使用:

filter (all isSpace)

迭代列表

  

我似乎不明白列表的迭代是如何工作的。

在Haskell中,列表是单链表:每个元素都包含一个值和对下一个值的引用。

因此,列表未编入索引:!!运算符必须遍历每个元素才能访问特定元素,从而在处理直接访问时使列表效率低下。

当你向一个函数提交一个列表时,你只需给它第一个元素。

考虑到这些因素,当您处理列表时,必须避免通过索引访问元素。

我们的想法是创建在简单值上完成工作并将它们映射到元素列表的函数。看一下toUpper函数:

toUpper :: Char -> Char

需要Char并返回其大写版本(也是Char)。

Haskell没有适用于toUpper的{​​{1}}函数,您必须使用Stringmap之类的内容将<$>应用于列表char(a toUpper):

String

这个想法是拥有只能做一件特定事情的功能。对列表进行Upercasing和迭代是两回事。 map toUpper "ab" -- "AB" toUpper <$> "ab" -- "AB" 函数是否需要知道它将大写的元素的索引?不!

迭代索引为

的列表

你可能会问:但如果我的函数真的需要考虑元素的索引怎么办? (即:用于滤除偶数或奇数元素)。

你有两种方法可以考虑它:

  • toUpper不是您需要使用的类型。也许Data.Map,Data.IntMap或Data.Vector更适合于任务(有关更多信息,请参阅这些模块),
  • 您需要使用保存索引的中间类型。

例如:

List

请注意,这也解决了您对增量函数的需求,因为索引是以您想要的任何值启动的。

要返回原始字符串,请写下:

let string = "abcde"
let indexedString = zip [1..] string

print indexedString -- [(1, 'a'), (2, 'b), (3, 'c), (4, 'd), (5, 'e)]

您需要使用map snd indexedString -- "abcde" fst函数来处理中间类型,或使用模式匹配:

snd

考虑指数:

filter (\x -> snd x == 'b') indexedString -- [(2, 'b')]
map (\(i,s) -> (i, toUpper s)) indexedString -- [(1,'A'),(2,'B'),(3,'C'),(4,'D'),(5,'E')]

注释

Haskell中已经存在let string = "abcde" indexedString = zip [1..] string upperEven (i, c) | even i = (i, toUpper c) | otherwise = (i, c) print $ map upperEven indexedString -- [(1,'a'),(2,'B'),(3,'c'),(4,'D'),(5,'e')] print $ map snd $ map upperEven indexedString -- "aBcDe" 函数,它被称为increment(它也是一个更通用的函数,适用于支持succ类的所有类型,如Int,Char ...)< / p>

答案 1 :(得分:0)

为什么不对文件中的内容使用words :: String -> [String]?如果每行有一个单词,则使用lines :: String -> [String]将是另一种选择。

然后,如果我的问题得到解决,您可以编写以下内容来解决问题:

import Data.List (findIndices)
import Data.Char (isUpper)

allUpperOneBasedIndices :: String -> [Int]
allUpperOneBasedIndices = map succ . findIndices (all isUpper) . words