Jer on Rails

Jeremy Weiskotten on web development, startups, beer, and other stuff.


Jay Fields: Array#collect_with_remaining

Jay Fields posted another interesting Ruby example and a call for alternate solutions. (Check his post out for problem details.) After some digging in the Ruby API docs and a lot of experimenting in tests and irb, here’s my offering:

def collect_with_remaining  enum_with_index.inject([]) do |result, (element, index)|    result << yield(element, values_at(*(0...size).to_a - [index]))  endend

I took the opportunity to learn about #enum_with_index, particularly how it’s used in conjunction with #inject. I also learned how the asterisk prefix expands an Array into parameters — I’ve seen this before somewhere (Rails source?) but never really understood what it was doing. It came in handy here, because I had an array but #values_at only takes Ranges or indices as raw parameters.

So how this method works…

  1. In order to get the elements of the array other than “element” at “index”, we create a range of every index in the array, (0…size).

  2. We convert this range to an array (#to_a) and we remove the index of the current element ( – [index]). This gives us an array of every index but the current element’s.
  3. We send the elements in this array to #values_at, thanks to the aforementioned asterisk notation, and we get ba all of the elements except for the current one.

One thing I don’t like about this solution is that it creates the same range of indexes and converts it to the same array of indexes for each element. If I did some profiling and weren’t happy with performance, I would pull that code out of the block so that it’s only done once, and would only add one line of code doing so.

Other than that, I think this example really benefits from the elegance afforded by Ruby, not to mention the powerful features of some core APIs. It’s terse but doesn’t seem too obtuse or obscure; while it uses some relatively advanced Ruby, it shouldn’t be too hard to figure out.

Tags:

Comments are closed.