映射整个数据集以获得结果

时间:2013-12-22 00:27:12

标签: haskell

假设我有数组:

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循环一样)以及如何获得输出?

3 个答案:

答案 0 :(得分:4)

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

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

在评论中,你说过你想要以相反的方式获得对比赛。

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

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开始的三条线越来越缩进,因为它们实际上是从哈斯克尔的角度来看的一行。

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

因此,我们可以使用nub中的Data.List来摆脱这种情况。 (在文件顶部添加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)]

答案 1 :(得分:1)

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

答案 2 :(得分:1)

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

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