[英]Haskell, zip the element of a list with its length
The next lines should show how its has to work.. 下一行应该说明它必须如何工作..
[14,2,344,41,5,666]
after [(14,2),(2,1),(344,3),(5,1),(666,3)]
[14,2,344,41,5,666]
[(14,2),(2,1),(344,3),(5,1),(666,3)]
之后[(14,2),(2,1),(344,3),(5,1),(666,3)]
["Zoo","School","Net"]
after [("Zoo",3),("School",6),("Net",3)]
["Zoo","School","Net"]
之后的[("Zoo",3),("School",6),("Net",3)]
Thats my code up to now 这是我的代码到目前为止
zipWithLength :: [a] -> [(a, Int)]
zipWithLength (x:xs) = zipWith (\acc x -> (x, length x):acc) [] xs
I want to figure out what the problem in the second line is. 我想弄清楚第二行的问题是什么。
If you transform the numbers into strings (using show
), you can apply length
on them: 如果将数字转换为字符串(使用
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)]
However, you cannot use the same function on a list of strings: 但是,您不能在字符串列表上使用相同的函数:
Prelude> zipWithLength ["Zoo","School","Net"]
[("Zoo",5),("School",8),("Net",5)]
The numbers are not the lengths of the strings, but of their representations: 这些数字不是字符串的长度,而是它们的表示形式:
Prelude> show "Zoo"
"\"Zoo\""
Prelude> length (show "Zoo")
5
As noted in the comments, similar problems may happen with other types of elements: 如评论中所述,其他类型的元素可能会出现类似问题:
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
If you want to apply a function on every element of a list, that is a map :: (a -> b) -> [a] -> [b]
. 如果你想在列表的每个元素上应用一个函数,那就是
map :: (a -> b) -> [a] -> [b]
。 The map thus takes a function f
and a list xs
, and generates a list ys
, such that the i -th element of ys
, is f
applied to the i -th element of xs
. 地图因而需要一个函数
f
和一个列表xs
,并生成列表ys
,使得第i个元件ys
,被f
施加到第i个元素xs
。
So now the only question is what mapping function we want. 所以现在唯一的问题是我们想要的映射功能。 We want to take an element
x
, and return a 2-tuple (x, length x)
, we can express this with a lambda expression : 我们想要一个元素
x
,并返回一个2元组(x, length x)
,我们可以用lambda表达式表达 :
mapwithlength = map (\x -> (x, length x))
Or we can use ap :: Monad m => m (a -> b) -> ma -> mb
for that: 或者我们可以使用
ap :: Monad m => m (a -> b) -> ma -> mb
:
import Control.Monad(ap)
mapwithlength = map (ap (,) length)
A problem is that this does not work for Int
s, since these have no length
. 问题是这不适用于
Int
,因为它们没有length
。 We can use show
here, but there is an extra problem with that: if we perform show
on a String
, we get a string literal (this means that we get a string that has quotation marks, and where some characters are escaped). 我们可以在这里使用
show
,但是还有一个额外的问题:如果我们在String
上执行show
,我们得到一个字符串文字(这意味着我们得到一个带引号的字符串,以及某些字符被转义的地方)。 Based on the question, we do not want that. 基于这个问题,我们不希望如此。
We can define a parameterized function for that like: 我们可以为它定义一个参数化函数:
mapwithlength f = map (ap (,) (length . f))
We can basically leave it to the user. 我们基本上可以将它留给用户。 In case they want to work with integers, they have to call it with:
如果他们想要使用整数,他们必须调用它:
forintegers = mapwithlength show
and for String
s: 对于
String
s:
forstrings = mapwithlength id
After installing the number-length
package, you can do: 安装
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))
Examples: 例子:
>>> withLength ["Zoo", "bear"]
[("Zoo",3),("bear",4)]
>>> withLength' [14, 344]
[(14,2),(344,3)]
As bli points out, calculating the length of a number using length (show n)
does not transfer to calculating the length of a string, since show "foo"
becomes "\\"foo\\""
. 正如bli指出的那样,使用
length (show n)
计算数字的长度不会转移到计算字符串的长度,因为show "foo"
变为"\\"foo\\""
。 Since it is not obvious what the length of something is, you could parameterise the zip function with a length function: 由于事物的长度不明显,您可以使用长度函数对zip函数进行参数化:
zipWithLength :: (a -> Int) -> [a] -> [(a, Int)]
zipWithLength len = map (\x -> (x, len x))
Examples of use: 使用示例:
> 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)]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.