Sign up ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

I watched a presentation by Dave Thomas on Elixir where he gave an example problem that he solved using functional programming. He mentioned using Ruby to solve the same problem, but did not show an example. I decided to give it a try. The problem goes something like this:

For a list (Ruby doesn't have lists, but for our purposes an Array is close enough) of n numbers, create a new list where unique numbers are represented once, and repeated numbers are represented by a tuple (again, Ruby doesn't have tuples, but for our purposes a Hash or an Array would do) where the first element is the number itself, and the second is its count.

For Example, the following list:

[ 1, 2, 2, 2, 3, 4, 4, 5, 6, 6, 6, 6 ]

Would become:

[ 1, {2, 3}, 3, {4, 2}, 5, {6, 3} ]

I came up with the following solution.

list = [ 1, 2, 2, 2, 3, 4, 4, 5, 6, 6, 6, 6 ]
list.each_with_object(Hash.new(0)) { |n, hash| hash[n] += 1 }.map { |k, v| v > 1 ? { k => v } : k }
#=> [ 1, {2 => 3}, 3, {4 => 2}, 5, {6 => 3} ]

How would you go about solving this problem?

share|improve this question

2 Answers 2

up vote 4 down vote accepted

Some notes:

  • From the moment you write hash[n] += 1, your solution is not functional anymore.
  • each_with_object is also imperative, for FP you should use reduce.
  • reduce works well with linked lists, not so well for generating new arrays. In any case, reduce is a generic abstraction, there is a more specific one to the problem at hand: Enumerable#chunk.

That's how I'd write it:

xs.chunk(&:itself).map { |y, ys| ys.size == 1 ? y : {y => ys.size} }
share|improve this answer
    
Thanks great. I am wondering about &:itself, there's no mention of it in the docs. Is that a shortcut or a keyword? –  Mohamad Apr 13 at 20:10
    
    
Ahhh, ok, I was looking at Enumerable. So I suppose &:itself translates to chunk { |n| n.itself }, also the same as chunk { |n| n } –  Mohamad Apr 13 at 20:12
    
@Mohamad that is correct, and by extension &:any_method is translated the same way –  Devon Parsons Apr 14 at 17:24
1  
Immutability is a key concept of functional programming. You can't change anything in-place (add, update, remove, and so on). goo.gl/4OyjP –  tokland Apr 15 at 18:46

I would write a slower but easier to read version:

def same_or_tuple(list)
    list.map {|x| if list.count(x) == 1 then x
                  else [x, list.count(x)] end}
        .uniq
end
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.