Haskell list comprehension 0's and 1's
I am trying to write a function
row :: Int -> Int -开发者_如何学Go> [Int]
row n v
that returns a list of n
integers, all 0
's, except for the v
th element, which needs to be a 1
.
For instance,
row 0 0 = []
row 5 1 = [1,0,0,0,0]
row 5 3 = [0,0,1,0,0]
I am new to Haskell and having a lot of difficulty with this. In particular I can't figure out how to make it repeat 0
's. I understand the concept of building a list from let's say [1..n]
, but I just get [1,2,3,4,5]
Any help with this would be greatly appreciated. Thank you.
Try:
let row n v = map (\x -> if x == v then 1 else 0) [1..n]
Here a "monadic" solution:
row n v = [(v-1, 0), (1, 1), (n-v, 0)] >>= (uncurry replicate)
The replicate
function repeats a given value a number of times, e.g. replicate (v-1) 0
gives a list of v-1
zeros. The uncurry
is used to modify the replicate
in order to accept a tuple instead of two single arguments. The funny operator >>=
is the heart of a monad; for lists it is the same as concatMap
with flipped arguments.
With a comprehensive list :
row n v = [if x == v then 1 else 0 | x <- [1..n]]
Or using fromEnum
(thanks dave4420)
row n v = [fromEnum (x == v) | x <- [1..n]]
This should also work:
row n v = replicate (v-1) 0 ++ [1] ++ replicate (n-v) 0
And yet another solution, recursively building up the list:
row :: Int -> Int -> [Int]
row 0 _ = []
row n 1 = 1 : (row (n-1) 0)
row n m = 0 : (row (n-1) (m-1))
And a more readable one, where zeros are "taken":
row :: Int -> Int -> [Int]
row 0 _ = []
row n m = take (m - 1) zeros ++ [1] ++ take (n - m) zeros
where zeros = (iterate id 0)
A simple recursive loop with two temporary variables c and lst . c is for counting and lst is list which we have to return.
row :: Int -> Int -> [ Int ]
row 0 0 = []
row n v = rowHelp n v 1 [] where
rowHelp n v c lst
| c > n = lst
| v == c = rowHelp n v ( c + 1 ) ( lst ++ [ 1 ] )
| otherwise = rowHelp n v ( c + 1 ) ( lst ++ [ 0 ] )
~
~
the fun with haskell is that it let's you write your program very much the way you would express the algorithm. So try:
row n v = [if (x `mod` v==0) then 1 else 0 | x <- [1..n] ]
At first you create a list from 1,2 to n. Then you check if the number is divisible by v, if it is, 1 is inserted in the output list, if not 0.
Examples:
> row 0 0
[]
> row 5 1
[1,0,0,0,0]
> row 5 3
[0,0,1,0,0]
> row 15 3
[0,0,1,0,0,1,0,0,1,0,0,1,0,0,1]
HTH Chris
I like to demonstrate a top down approach, based on Chris's solution:
row n v = result
where
result = take n numbers -- our result will have a length of n
numbers = map trans [1,2,..] -- and is some transformation of
-- the list of natural numbers
trans e
| e `mod` v == 0 = 1 -- let every v-th element be 1
| otherwise = 0 -- 0 otherwise
This style emphasizes the idea in functional programming that one writes down what a certain value like row n v
is supposed to be, rather than trying to write down what a function does. In reminiscence of a well known joke about the lesser known pragramming language Sartre one could say that in pure functional programming functions do nothing, they just are.
精彩评论