views:

158

answers:

6

Hey guys,

is there an easy way. To take a list of numbers, say 123456. Then multiply the odd placed by three and the even placed by 1.

i.e. (1 * 3) + (2 * 1) + (3 * 3) + (4*1) + (5*3) + (6*1)

i was thinking the map function somewhere along the lines. But i don't know how to map *3 to just the odd placed values. Oh and if you could give me the version not in prelude that would be great like the actual function or functions, as if its being imported from an external haskell file

Thanks for the help

A: 

Unfortunately I have no Haskell at hand, but it should be no problem to write a function, that takes an integer as an argument and checks wether it's odd or even and then multiplies it by three if it's odd. That function can than be applied to the list via map (as you said).

I'm trying it (not sure if it's correct Haskell syntax):

yourFunc :: Integer -> Integer
yourFunc a =
  if (a 'mod' 2) == 0 
  then a
  else a * 3
phimuemue
1) Those should be backticks, not single quotes2) don't use (`mod` 2), use "odd" and "even" as needed3) indent the "then" and "else more than the "if".4) This doesn't solve his issue as he wants to multiply by three (or one) based on the __index__ of the value, not the value itself.
TomMD
umm you misinterpreted what i meant. The numbers might not be odd or even themselves. Its just their place value. thanks Tom, got there before me
Abstract
+1  A: 

You can still use map, just use zip first:

let list' = zip [1..] list
in map (\(cnt,val) -> if odd cnt then val * 3 else val) list'

Above you can see how to make a result dependent on the index as well as the value at that index. This is a fairly general solution that, by replacing the lambda (first argument of map), you can make many variants. The more specialized solution using cycle and zipWith is much shorter and perfectly readable to those comfortable in Haskell.

edited and fleshed out after the statement this is not homework.

TomMD
can you explain that a little further?
Abstract
I intentionally left it as a (very large) hint until you answered the "is this homework" question. This is basically done, I don't see what further really needs explained.
TomMD
mmk i'll search elsewhere then, i understand but that only gets me a list of tuples, with the place value on the left, value of the integer on the right. Thats fantastic but what you do there i can only seem to grab one of those two variables. Nor can i put a filter to just grab the odd or even ones. Whats this homework thing (for the second time)
Abstract
Is this even Haskell?
jasonmp85
Yes, it is Haskell. And Abstract, if you don't know what Homework is then you can read its [definition](http://en.wikipedia.org/wiki/Homework) and answer yes or no.
TomMD
oh i didn't realise you guys actually meant homework from school. Nah its called we do C at Uni and i wanted to learn haskell on the side, so i'm attempting my task 1 in haskell. Its not part of the course or anything just an interest
Abstract
+1  A: 
Dominic Cooney
This is the most direct implementation of the task, but it seems a bit hard to read. Maybe it's just my lack of experience with this style, but it feels like the reading order is all wonky (the actual behavior is spread out between arguments and arguments to arguments) and the punctuation outweighs the semantic characters. `($) ( ( [(() ), (() )]) )` — holy cow!
Chuck
@Chuck You could introduce "explaining bindings" with `let` and `where` if you like.
Dominic Cooney
yeah okay i'm only a beginner with haskell, that looks mega confusing can;'t we put some $'s in there somewhere to clear it up. Too many brackets
Abstract
Maybe `sum (zipWith (*) (cycle [1,3]) xs)` is a bit clearer in this case?
yatima2975
@yatima2975 minus the `sum`—I think @Abstract wants the result as a list—`zipWith` is *much* neater. You should submit this as an answer.
Dominic Cooney
+1 on the `zipWith`, it's a much more readable solution.
jasonmp85
`((*) 3)` can be much more easily written as `(*3)`. These are called operator sections and are worth learning.
MtnViewMark
thanks all for the help :). Yatima thats awesome, i actually fully understand that.
Abstract
+13  A: 

Okay, as I wrote in a comment earlier, zipWith (*) (cycle [3,1]) xs is what you're looking for. But first, a minor nitpick: the head of the list I would call the zeroth element, that's why I have switched the 1 and 3 around :-)

Let's go through a simple example; let xs be [9,8,7,3,2]. cycle [3,1] just repeats its argument over and over so that will be an infinite list starting with [3,1,3,1,3,1,..]. What zipWith f xs ys does is take the head element of xs and the head element of ys and apply f (which should be a function of two arguments) to those elements - the result of f then goes onto the front of the result of zipWith. If one of xs or ys becomes empty, we're done; otherwise we just keep going.

So the first element of the result will be (3 * 9), then (1 * 8), (3 * 7), (1 * 3), (3 * 2) and we're done!

You can have a look at the definition of zipWith here.

If you really don't want to use the predefined functions, you could define an 'alternating map' taking two functions instead of one, applying the first of these to the head of your argument list and switching the functions around on the recursive call. I'll let you figure out the details there...

yatima2975
yatima2975: `pointFreeSol = zipWith (*) (cycle [3,1])`
yairchu
Yeah, you're right. The `xs` does seem to come out of nowhere! I should just have named the function.
yatima2975
A: 

If you want to do this point-free style, there's no better way than using cycle and some form of zip. (Point-free means, roughly, "without naming let-bound or lambda-bound variables.") I have two questions:

  • How many different ways will you need to generalize this computation?
  • How familiar are your readers with cycle and other lesser-known list functions (there must be a hundred list functions)?

The more general your problem and the more familiar your readers, the more likely I am to recommend point-free style. For a one-off solution aimed at readers not very familiar with Haskell, I might try a recursive function:

mult31 [] = 0
mult31 [x:x':xs] = x * 3 + x' * 1 + mult31 xs
mult31 [x] = x * 3

Or if you want to get clever, you can use a pair of alternating functions:

mult31 = m3
  where m3 (x:xs) = x * 3 + m1 xs
        m3 []     = 0
        m1 (x:xs) = x * 1 + m3 xs
        m1 []     = 0

Either of these functions will seem less natural to a Haskell veteran than something that uses a zip function with cycle, but for someone just starting out, they may be easier to follow.

Norman Ramsey
nah Zipwith and cycle work really well but thanks for the help : )
Abstract
A: 

My first thought was to use an accumulating map, using the accumulating parameter to flag whether it's on an 'even' or 'odd' cycle. I see nobody else has done that so let's see how it goes...

import Data.List (mapAccumL)

yourFunc = snd . mapAccumL mult True -- 'True' represents an odd index, starting from 1
  where
    mult True  x = (False, 3 * x)
    mult False x = (True , x)
Nefrubyr

related questions