【问题标题】:mapping over entire data set to get results映射整个数据集以获得结果
【发布时间】:2013-12-22 00:27:11
【问题描述】:

假设我有数组:

A = "ABACUS"

B = "YELLOW"

它们被压缩成这样:Pairing = zip A B

我还有一个函数Connect :: Char -> [(Char,Char)] -> [(Char,Char,Int)]

我想要做的是给定一个字符,例如 A,找到它在第一个字符串中出现的位置的索引,并返回第二个字符串中相同位置的字符,以及位置,例如如果我做了 Connect 'A' Pairing 我想要 (A,Y,0) 和 (A,L,2) 作为结果。

我知道我能做到

pos = x!!map fst pairing 

检索位置。和fnd = findIndices (==pos) map snd pairing 获取第二个字符串中此位置的内容,但在 Haskell 中,我将如何对整个数据集执行此操作(就像我使用 for 循环一样)以及如何获得输出?

【问题讨论】:

    标签: haskell


    【解决方案1】:

    要完全按照您的要求进行(但将函数名称的首字母更正为小写),我可以定义

    connect :: Char -> [(Char,Char)] -> [(Char,Char,Int)]
    connect c pairs = [(a,b,n)|((a,b),n) <- zip pairs [0..], a == c]
    

    如果

    pairing = zip "ABACUS" "YELLOW"
    

    我们得到

    ghci> connect 'A' pairing
    [('A','Y',0),('A','L',2)]
    

    但是,我认为使用zip3 压缩一次而不是两次会更整洁:

    connect3 :: Char -> String -> String -> [(Char,Char,Int)]
    connect3 c xs ys = filter (\(a,_,_) -> a==c) (zip3 xs ys [0..])
    

    相当于

    connect3' c xs ys = [(a,b,n)| (a,b,n) <- zip3 xs ys [0..], a==c]
    

    它们都按您的意愿工作:

    ghci> connect3 'A' "ABACUS" "YELLOW"
    [('A','Y',0),('A','L',2)]
    ghci> connect3' 'A' "ABACUS" "AQUAMARINE"
    [('A','A',0),('A','U',2)]
    

    在 cmets 中,您说您希望反过来获得配对。

    这一次,使用单子do 表示法最为方便,因为列表是单子的一个示例。

    connectEither :: (Char,Char) -> String -> String -> [(Char,Char,Int)]
    connectEither (c1,c2) xs ys = do
       (a,b,n) <- zip3 xs ys [0..]
       if  a == c1 then return (a,b,n) else
        if b == c2 then return (b,a,n) else 
         fail "Doesn't match - leave it out"
    

    我使用了fail 函数来排除不匹配的内容。以ififfail 开头的三行越来越缩进,因为从 Haskell 的角度来看,它们实际上是一行。

    ghci> connectEither ('a','n') "abacus" "banana"
    [('a','b',0),('a','n',2),('n','u',4)]
    

    在这种情况下,它没有包含('n','a',2),因为它只检查一种方式。

    我们可以通过重用现有函数来实现这两种方式:

    connectBoth :: (Char,Char) -> String -> String -> [(Char,Char,Int)]
    connectBoth (c1,c2) xs ys = lefts ++ rights where
          lefts  = connect3 c1 xs ys
          rights = connect3 c2 ys xs
    

    这给了我们想要得到的一切:

    ghci> connectBoth ('a','n') "abacus" "banana"
    [('a','b',0),('a','n',2),('n','a',2),('n','u',4)]
    

    但不幸的事情不止一次:

    ghci> connectBoth ('A','A') "Austria" "Antwerp"
    [('A','A',0),('A','A',0)]
    

    所以我们可以使用来自Data.Listnub 来摆脱它。 (在文件顶部添加import Data.List。)

    connectBothOnce (c1,c2) xs ys = nub $ connectBoth (c1,c2) xs ys
    

    给予

    ghci> connectBothOnce ('A','A') "ABACUS" "Antwerp"
    [('A','A',0),('A','t',2)]
    

    【讨论】:

    • 感谢您花时间向我展示不同的方法。非常感谢!
    • 如果我有一个字符元组作为输入 (Char,Char) 这样 [link]connect :: (Char,Char) -> [(Char,Char)] -> [( Char,Char,Int)] 我怎么能拥有它,以便它也将第二个字符串中的配对返回到第二个元组?即 ghci> connect ('A','E') "ABACUS" "YELLOW" [('A','Y',0),('A','L',2),('E',' B',1)??
    • 你的意思是connect ('A','E') "ABACUS" "YELLOW" 应该是[('A','Y',0),('A','L',2),('B','E',1)],因为E 是第二个它是第二个字符串?如果是这样,您需要connect3'' (c1,c2) xs ys = [(a,b,n)| (a,b,n) &lt;- zip3 xs ys [0..], a==c1 || b==c2]。如果没有,请告诉我。
    • 不,我需要它返回我所说的。我会解释为什么我需要这样的上下文,但这需要太长时间哈!
    • 应该回答connect ('A','A') "ABACUS" "ANTWERP"[('A','A')]还是[('A','A'), ('A','A')]
    【解决方案2】:

    我建议不要将列表压缩在一起,因为这只会增加使用来自Data.List 的函数elemIndices 的难度。然后,您有一个索引列表,您可以直接使用这些索引从第二个列表中获取值。

    【讨论】:

      【解决方案3】:

      您可以使用另一个zip 添加索引,然后过滤给定的字符并将元组转换为三元组。特别是由于这种重新包装,列表推导似乎很合适:

      connect c pairs = [(a, b, idx) | ((a, b), idx) <- zip pairs [0..], a == c]
      

      【讨论】:

      • 之前尝试通过列表理解来解决这个问题,但最终在构建代码方面让自己感到困惑!我将在哪里编写获取索引的代码?
      猜你喜欢
      • 1970-01-01
      • 2017-07-26
      • 1970-01-01
      • 2015-08-23
      • 2023-03-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-26
      相关资源
      最近更新 更多