Ruby deck flips

posted by pete on April 14th, 2009

I’m constantly reminded of why I love Ruby so damn much. I’m not a CompSci scholar, and I know that Lisp did everything first 30 years ago… I guess it’s all about context, isn’t it?

Luckily, this isn’t Reddit and so I’m hoping I can share one of my favourite operators with you. That’s right, I have favourite operators. They make me feel like I have crazy ninja Skate or Die skills, even though there’s very little mystery.

In Ruby we kick around && and || like nerd footbags, but there are a few operators that you might not have realized, and & is one of them.

& (aka the Intersect)

You can be forgiven if, like me, you initially assume that & is a bitwise AND operator. After all, when applied to a Numeric, that’s exactly what it is. (In brief, 1 & x returns 1 when x is an odd number and 0 if x is even. Good for alternating row colours!)

When applied to two Array objects, it returns the elements that are unique in both:

[1, 2, 3] & [2, 3, 4] # => [2, 3]


How many times have you written inefficient double-loop constructs to compare lists? There’s something deeply satisfying about replacing functions with a single character.

What can you do with this little gem? One of my favourites is a simple function to derive the Tanimoto coefficient. This gives you a Float between 0 and 1 which tells you how similar the contents of two lists are. This is useful for correlating tastes, recommending products, and other predictive applications.

def tanimoto(a, b)
  c = a & b
  c.size.to_f / (a.size + b.size - c.size)
end

x = %w[apple orange banana kiwi]
y = %w[apple pear orange]

puts tanimoto(x, y) # => 0.4

6 Responses to “Ruby deck flips

  1. Daniel Haran Says:
    April 14th, 2009 at 12:50 PM

    Funny you’d mention Tanimoto/Jaccard: I’ve put code in the wild that uses it, which of course uses & for array intersection.

    Yes, this is a shameless plug for “people you may know”, code for a feature you’re familiar with on facebook or linkedin, all in Ruby: http://github.com/danielharan/people_you_may_know/tree/master

  2. Luigi Montanez Says:
    April 14th, 2009 at 10:18 PM

    I like using the minus operator on Arrays:

    [1,2,3] - [2,3,4] # => [1]

    Useful for situations where you need to determine stragglers, like a list of friends who haven’t yet RSVPed to an event.

    your_friends_list - your_birthday_party_attendees # => not_really_your_friends
  3. Jamie Macey Says:
    April 15th, 2009 at 01:44 PM

    1 & anything else most certainly will not always return 0.

    0b0001 & 0b???0 (an even number) will return 0
    0b0001 & 0b???1 (an odd number) will return 1
    
  4. Pete Forde Says:
    April 15th, 2009 at 06:28 PM

    Nice catch, Jamie!

    I wrote one thing and changed my example. This should learn me not to blog at 3am.

  5. Srdjan Pejic Says:
    April 30th, 2009 at 09:27 PM

    You know, I’m reading Programming Collective Intelligence in which one of the early chapters talks about recommendation systems and the Tanimoto coefficient.

    I can’t recall the code exactly, but it was hell of a lot longer than that when he set about comparing dictionaries in Python.

    Thanks, Pete.

  6. Swaroop Rao Says:
    June 4th, 2009 at 07:02 AM

    When you wrote “When applied to two Array objects, it returns the elements that are unique in both” with reference to the AND operator, I think you meant “common to”, not “unique in”. I would interpret “unique” as meaning “no duplicates” or “no repetitions”, which is NOT what you were trying to convey here, in my opinion.

    Notwithstanding that, I have recently discovered your “blog” and found it utterly fascinating. Your article titled “Open Says Me” was eye-openingly, jaw-droppingly innovative. I’m not a Ruby guy (although I know Ruby, I don’t have the freedom to use it as much as I would like to), but I’ll still look forward to using the pattern you have described in that article on one of my projects.

    Regards, Swaroop Rao

Leave a Reply