我正在尝试根据相对于前一个元素的顺序对列表中的项目进行编号,例如" book"在下面的列表中。
[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"]
&#34; title&#34;计数重新开始为1和&#34;作者&#34;在一本新的&#34;书&#34;满足了。 我可以轻松地为这些书编号,但我不知道如何根据书号对其他项目进行编号。
所以我尝试在列表理解中组合一个zip,如下所示:
[(1,"title"),(2,"author"),(3,"title"),(4,"title"),(5,"author")]
但我得到的是:
http://query.yahooapis.com/v1/public/yql
结果是元组还是列表并不重要。
我非常感谢你的帮助。
谢谢, 奥马
答案 0 :(得分: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' _ _ [] = []
答案 1 :(得分:0)
有许多用于累积列表的函数。在这种情况下,我们想要map
之类的东西,除了我们需要携带前面元素的信息。执行此操作的函数是scanl :: (s -> a -> s) -> s -> [a] -> [s]
。
你最好积累一对整数而不是浮点数。浮动是不精确的,所以你可能会得到一些你想要的东西。让我们说s = (Int, Int)
并创建步骤函数。
step :: (Int, Int) -> String -> (Int, Int)
step (a, b) s@"book" = (a + 1, 0 )
step (a, b) s@"title" = (a , b + 1)
step (a, b) s@"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
生成初始状态作为第一个元素,但我们不想要它。这可以通过tail
或drop 1
轻松删除(tail
是可以的,因为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)