Haskell,压缩列表的元素及其长度
Haskell, zip the element of a list with its length
接下来的几行应该说明它是如何工作的..
[14,2,344,41,5,666]
在 [(14,2),(2,1),(344,3),(5,1),(666,3)]
之后
["Zoo","School","Net"]
在 [("Zoo",3),("School",6),("Net",3)]
之后
这就是我目前的代码
zipWithLength :: [a] -> [(a, Int)]
zipWithLength (x:xs) = zipWith (\acc x -> (x, length x):acc) [] xs
我想弄清楚第二行的问题是什么
如果将数字转换为字符串(使用 show
),则可以对它们应用 length
:
Prelude> let zipWithLength = map (\x -> (x, length (show x)))
Prelude> zipWithLength [14,2,344,41,5,666]
[(14,2),(2,1),(344,3),(41,2),(5,1),(666,3)]
但是,您不能对字符串列表使用相同的函数:
Prelude> zipWithLength ["Zoo","School","Net"]
[("Zoo",5),("School",8),("Net",5)]
数字不是字符串的长度,而是它们的表示:
Prelude> show "Zoo"
"\"Zoo\""
Prelude> length (show "Zoo")
5
如评论中所述,其他类型的元素可能会出现类似问题:
Prelude> zipWithLength [(1.0,3),(2.5,3)]
[((1.0,3),7),((2.5,3),7)]
Prelude> show (1.0,3)
"(1.0,3)"
Prelude> length (show (1.0,3))
7
如果你想对列表的每个元素应用一个函数,那就是 map :: (a -> b) -> [a] -> [b]
。因此,映射接受一个函数 f
和一个列表 xs
,并生成一个列表 ys
,这样 i 的第 [=] 个元素18=],是 f
应用于 xs
的第 i 个元素。
所以现在唯一的问题是我们想要什么映射函数。我们想取一个元素 x
,return 一个二元组 (x, length x)
,我们可以用 lambda 表达式:
mapwithlength = map (\x -> (x, length x))
或者我们可以使用 ap :: Monad m => m (a -> b) -> m a -> m b
:
import Control.Monad(ap)
mapwithlength = map (ap (,) length)
一个问题是这对 Int
不起作用,因为它们没有 length
。我们可以在这里使用 show
,但是还有一个额外的问题:如果我们在 String
上执行 show
,我们得到一个字符串文字(这意味着我们得到一个具有引号,以及一些字符被转义的地方)。根据问题,我们不希望那样。
我们可以为此定义一个参数化函数:
mapwithlength f = map (ap (,) (length . f))
我们基本上可以交给用户。如果他们想使用整数,则必须使用以下方式调用它:
forintegers = mapwithlength show
和 String
s:
forstrings = mapwithlength id
安装 number-length
软件包后,您可以:
module Test where
import Data.NumberLength
-- use e.g for list of String
withLength :: [[a]] -> [([a], Int)]
withLength = map (\x -> (x, length x))
-- use e.g for list of Int
withLength' :: NumberLength a => [a] -> [(a, Int)]
withLength' = map (\x -> (x, numberLength x))
示例:
>>> withLength ["Zoo", "bear"]
[("Zoo",3),("bear",4)]
>>> withLength' [14, 344]
[(14,2),(344,3)]
正如 bli 指出的那样,使用 length (show n)
计算数字的长度不会转换为计算字符串的长度,因为 show "foo"
变成了 "\"foo\""
。由于某些东西的 length 是什么并不明显,您可以使用长度函数参数化 zip 函数:
zipWithLength :: (a -> Int) -> [a] -> [(a, Int)]
zipWithLength len = map (\x -> (x, len x))
使用示例:
> zipWithLength (length . show) [7,13,666]
[(7,1),(13,2),(666,3)]
> zipWithLength length ["Zoo", "School", "Bear"]
[("Zoo",3),("School",6),("Bear",4)]
> zipWithLength (length . concat) [[[1,2],[3],[4,5,6,7]], [[],[],[6],[6,6]]]
[([[1,2],[3,4],[5,6,7]],7),([[],[],[6],[6,6]],3)]
接下来的几行应该说明它是如何工作的..
[14,2,344,41,5,666]
在 [(14,2),(2,1),(344,3),(5,1),(666,3)]
["Zoo","School","Net"]
在 [("Zoo",3),("School",6),("Net",3)]
这就是我目前的代码
zipWithLength :: [a] -> [(a, Int)]
zipWithLength (x:xs) = zipWith (\acc x -> (x, length x):acc) [] xs
我想弄清楚第二行的问题是什么
如果将数字转换为字符串(使用 show
),则可以对它们应用 length
:
Prelude> let zipWithLength = map (\x -> (x, length (show x)))
Prelude> zipWithLength [14,2,344,41,5,666]
[(14,2),(2,1),(344,3),(41,2),(5,1),(666,3)]
但是,您不能对字符串列表使用相同的函数:
Prelude> zipWithLength ["Zoo","School","Net"]
[("Zoo",5),("School",8),("Net",5)]
数字不是字符串的长度,而是它们的表示:
Prelude> show "Zoo"
"\"Zoo\""
Prelude> length (show "Zoo")
5
如评论中所述,其他类型的元素可能会出现类似问题:
Prelude> zipWithLength [(1.0,3),(2.5,3)]
[((1.0,3),7),((2.5,3),7)]
Prelude> show (1.0,3)
"(1.0,3)"
Prelude> length (show (1.0,3))
7
如果你想对列表的每个元素应用一个函数,那就是 map :: (a -> b) -> [a] -> [b]
。因此,映射接受一个函数 f
和一个列表 xs
,并生成一个列表 ys
,这样 i 的第 [=] 个元素18=],是 f
应用于 xs
的第 i 个元素。
所以现在唯一的问题是我们想要什么映射函数。我们想取一个元素 x
,return 一个二元组 (x, length x)
,我们可以用 lambda 表达式:
mapwithlength = map (\x -> (x, length x))
或者我们可以使用 ap :: Monad m => m (a -> b) -> m a -> m b
:
import Control.Monad(ap)
mapwithlength = map (ap (,) length)
一个问题是这对 Int
不起作用,因为它们没有 length
。我们可以在这里使用 show
,但是还有一个额外的问题:如果我们在 String
上执行 show
,我们得到一个字符串文字(这意味着我们得到一个具有引号,以及一些字符被转义的地方)。根据问题,我们不希望那样。
我们可以为此定义一个参数化函数:
mapwithlength f = map (ap (,) (length . f))
我们基本上可以交给用户。如果他们想使用整数,则必须使用以下方式调用它:
forintegers = mapwithlength show
和 String
s:
forstrings = mapwithlength id
安装 number-length
软件包后,您可以:
module Test where
import Data.NumberLength
-- use e.g for list of String
withLength :: [[a]] -> [([a], Int)]
withLength = map (\x -> (x, length x))
-- use e.g for list of Int
withLength' :: NumberLength a => [a] -> [(a, Int)]
withLength' = map (\x -> (x, numberLength x))
示例:
>>> withLength ["Zoo", "bear"]
[("Zoo",3),("bear",4)]
>>> withLength' [14, 344]
[(14,2),(344,3)]
正如 bli 指出的那样,使用 length (show n)
计算数字的长度不会转换为计算字符串的长度,因为 show "foo"
变成了 "\"foo\""
。由于某些东西的 length 是什么并不明显,您可以使用长度函数参数化 zip 函数:
zipWithLength :: (a -> Int) -> [a] -> [(a, Int)]
zipWithLength len = map (\x -> (x, len x))
使用示例:
> zipWithLength (length . show) [7,13,666]
[(7,1),(13,2),(666,3)]
> zipWithLength length ["Zoo", "School", "Bear"]
[("Zoo",3),("School",6),("Bear",4)]
> zipWithLength (length . concat) [[[1,2],[3],[4,5,6,7]], [[],[],[6],[6,6]]]
[([[1,2],[3,4],[5,6,7]],7),([[],[],[6],[6,6]],3)]