2017-03-14 41 views
0

我想根据它们相对于前一个元素的顺序来编号列表中的项目,如下面列表中的“book”。Haskell:在列表中编号的项目

myList=["book","book","title","author","title","book","title","book", "author"] 

我想有:为“标题”和新的“书”后“作家”,在1

[book 1, book 2, title 2.1, author 2.1, title 2.2, book 3, title 3.1, book 4, author 4.1] 

将重新开始计数得到满足。 我可以编号的书,但我不知道如何编号取决于书号的其他项目。

,所以我想一个压缩列表中的理解结合起来,就像这样:

zip [fst (head (zip[1..][x | x <- myList, x=="book"]))..][x | x <- myList, x=="title" || x=="author"] 

,但我得到的是:

[(1,"title"),(2,"author"),(3,"title"),(4,"title"),(5,"author")] 

如果结果是一个元组不要紧或一个列表。

我真的很感谢你的帮助。

感谢, 奥马尔

回答

2

您可以使用一个辅助功能,使计数变量的轨迹:

number xs = number' 0 0 xs 
number' n m (x:xs) | x == "book" = (x,n+1,0) : number' (n+1) 0 xs 
number' n m (x:xs) | otherwise = (x,n,m+1) : number' n (m+1) xs 
number' _ _ [] = [] 
+0

谢谢!有用。 – omar

+0

作为跟进问题。我尝试将元组列表转换为像这样的列表列表:map(\(a,b,c) - > [a,b,c])[(“book”,1,0)....]我得到以下错误消息:没有实例(Num [Char])由于使用....引起的问题,因为只有字符串的元组,转换工作正常。任何想法为什么?再次感谢 – omar

+0

haskell中的列表是同质的,不支持不同类型的混合。 – rubystallion

0

有许多功能积累对列表。在这种情况下,我们需要像map之类的东西,除了我们需要从前面的元素中提取信息。一个这样做的函数是scanl :: (s -> a -> s) -> s -> [a] -> [s]

你最好积累一对整数而不是浮点数。花车是不精确的,所以你最终可能会得到你想要的东西以外的东西。可以说s = (Int, Int)并创建阶梯功能。

step :: (Int, Int) -> String -> (Int, Int) 
step (a, b) [email protected]"book" = (a + 1, 0 ) 
step (a, b) [email protected]"title" = (a , b + 1) 
step (a, b) [email protected]"author" = (a , b + 1) 
step x  _   = x 

当我们看到"book"我们添加1到左整和右整设置为0。当我们看到"title""author"时,我们将1添加到正确的整数并保留左整数相同。否则,我们将两个整数保持相同。您可以根据需要进行修改。

scanl step (0, 0) myList 
= [(0,0),(1,0),(2,0),(2,1),(2,2),(2,3),(3,0),(3,1),(4,0),(4,1)] 

我们需要做两件最后的事情。首先,scanl产生初始状态作为第一个元素,但我们不希望它。这很容易下降taildrop 1tail是好的,因为scanl总是产生一个非空列表,但许多人宁愿看到drop 1反正)。其次,我们想用适当的字符串来扩充每个元组。

zipWith (\s (a, b) -> (s, a, b)) <*> drop 1 . scanl step (0, 0) 

如果你不熟悉<*>(<*>) f g x = f x (g x)(在这种情况下)。我们也可以这样写:

\xs -> zipWith (\s (a, b) -> (s, a, b)) xs ((drop 1 . scanl step (0, 0)) xs) 
相关问题