Showing posts with label arrays. Show all posts
Showing posts with label arrays. Show all posts

Thursday, 11 June 2009

On the premature death of Array.to_a

hmm... after finally discovering that Array.to_a doesn't double-array now I'm getting warnings that Array.to_a is being obsoleted (with the unhelpful message: warning: default `to_a' will be obsolete). Aunty google tells me I should now use Array(thing)!

Can I just say (from a purely aesthetic POV):
yuk!

When you use to_a you can just read your code left-to-right eg:

Thing.do_stuff(args).to_a.do_something_else

You get a clear idea of what order your messages are passed in.
but having to use a stonking great Array() around one section means you have to jump back to the left again!

Array(Thing.do_stuff(args)).do_something_else

You have to read left-right-left-right :P
It's not as pretty.

So why exactly are they obsoleting Array.to_a ???

Tuesday, 28 October 2008

Enumerable.average

Was looking around for a quickie function to do an average on an Enumerable/Array just like max and min - and found there isn't one. So here's a quick-n-dirty one that you can drop into config/environment.rb. Examples for use in the comments:

module Enumerable
  # returns a simple average of each item
  # If a block is passed - it will try to perform the operation on the item.
  # if the result is nil - it won't be counted towards the average.
  # Egs: 
  # [1,2,3].average == 2
  # ["a","ab","abc"].average &:length == 2
  # @purchases.average &:item_price == 10.45
  def average(&block)
    the_sum = 0
    total_count = 0
    self.each do |item|
      # either the actual item, or a method called on the item
      next_value = block_given? ? yield(item) : item
      unless next_value.nil?
        the_sum += next_value
        total_count += 1
      end
    end
    return nil unless total_count > 0
    the_sum / total_count
  end
end

I used it for displaying neat averages in the view thus:

    <p>Averages:
    <br />Number of items: <%= @purchases.average &:num_items -%>
    <br />Unit price: <%= @purchases.average &:price -%>
    <br />Total price: <%= @purchases.average {|p| p.num_items * p.price } -%> </p>

Thursday, 10 April 2008

Array.item_after(this)

There are just so many really useful functions in Ruby that every time I look I find something new and funky. So it always surprises me when I look to find something I'd expect to see - that just isn't there.

I was hoping to find an array function that returns "the next item in the list from the given one". I have a set of steps in a workflow all stored in a list. Given the current step, I want to know what the next one is going to be... so that I can send the user on to the next action from the current one.

Luckily Ruby is really easy to extend. ;)

These functions will return the item before/after the given item... or an item of any given offset from the current one. They return nil if the item can't be found in the given list or if the offset would put the index outside the bounds of the array.

class Array
  def item_after(item)
    offset_from(item, 1)
  end
  def item_before(item)
    offset_from(item, -1)
  end
  def offset_from(match, offset = 1)
    return nil unless idx = self.index(match)
    self[idx + offset]
  end
end

Usage:

>> arr = ['a','b','c','d']
=> ["a", "b", "c", "d"]
>> arr.item_after('a')
=> "b"
>> arr.item_before('d')
=> "c"
>> arr.offset_from('a',2)
=> "c"
>> arr.offset_from('d',-3)
=> "a"
>> arr.offset_from('d',10)
=> nil
>> arr.item_after('purple')
=> nil