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?
2 Answers 2
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 usereduce
.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} }
-
-
\$\begingroup\$ ruby-doc.org/core-2.2.1/Object.html#method-i-itself \$\endgroup\$tokland– tokland2015年04月13日 20:11:33 +00:00Commented Apr 13, 2015 at 20:11
-
\$\begingroup\$ Ahhh, ok, I was looking at Enumerable. So I suppose
&:itself
translates tochunk { |n| n.itself }
, also the same aschunk { |n| n }
\$\endgroup\$Mohamad– Mohamad2015年04月13日 20:12:43 +00:00Commented Apr 13, 2015 at 20:12 -
\$\begingroup\$ @Mohamad that is correct, and by extension
&:any_method
is translated the same way \$\endgroup\$Devon Parsons– Devon Parsons2015年04月14日 17:24:54 +00:00Commented Apr 14, 2015 at 17:24 -
1\$\begingroup\$ Immutability is a key concept of functional programming. You can't change anything in-place (add, update, remove, and so on). slideshare.net/slideshow/… \$\endgroup\$tokland– tokland2015年04月15日 18:46:53 +00:00Commented Apr 15, 2015 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
Explore related questions
See similar questions with these tags.