【问题标题】:Getting elements from a list by an index list通过索引列表从列表中获取元素
【发布时间】:2015-12-27 04:15:21
【问题描述】:

我在 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中删除它们。

【问题讨论】:

  • 谢谢你给我的问题减分(!)
  • @Kevin Guan,谢谢!
  • 那是截图。
  • 网站不接受。所以,我不得不做一个屏幕截图。对不起。
  • 网站怎么不接受?因为你不能保持正确的格式?

标签: list haskell


【解决方案1】:

过滤空元素

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

代码已经过滤掉了空元素!看下面一行:

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

这一行做了两件事:

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

如果你所说的空元素是指只包含空格字符或什么都不包含的字符串,你可以改用:

filter (all isSpace)

遍历列表

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

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

因此列表没有索引:!! 运算符必须遍历每个元素才能访问特定元素,这使得列表在处理直接访问时完全低效。

当您向函数提交列表时,您只需为其提供第一个元素。

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

这个想法是创建函数来处理简单的值并将它们映射到元素列表。看看toUpper函数:

toUpper :: Char -> Char

它接受Char 并返回其大写版本(也是Char)。

Haskell 没有适用于StringtoUpper 函数,您必须使用map&lt;$&gt; 之类的函数将toUpper 应用于char 列表(String):

map toUpper "ab" -- "AB"
toUpper <$> "ab" -- "AB"

我们的想法是拥有只做一件特定事情的功能。大写和迭代列表是两件不同的事情。 toUpper 函数是否需要知道它将大写的元素的索引?不!

使用索引遍历列表

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

你有两种考虑方式:

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

例如:

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

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

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

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

map snd indexedString -- "abcde"

您需要使用fstsnd 函数来处理中间类型,或者使用模式匹配:

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')]

考虑索引:

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 函数已经存在于 Haskell 中,它被称为 succ(它也是一个更通用的函数,适用于支持 Enum 类的所有类型,如 Int、Char……)

【讨论】:

    【解决方案2】:

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

    如果我解决了您的问题,您可以编写以下内容来解决您的问题:

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

    【讨论】:

      猜你喜欢
      • 2013-12-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多