Categories
Uncategorized

Enumerating Enumerable: Enumerable#grep

Enumerating Enumerable

Once again, it’s Enumerating Enumerable time! This is the latest in my series of articles where I set out to make better documentation for Ruby’s Enumerable module than Ruby-Doc.org’s. In this installment, I cover the grep method.

In case you missed any of the previous articles, they’re listed and linked below:

  1. all?
  2. any?
  3. collect / map
  4. count
  5. cycle
  6. detect / find
  7. drop
  8. drop_while
  9. each_cons
  10. each_slice
  11. each_with_index
  12. entries / to_a
  13. find_all / select
  14. find_index
  15. first

Enumerable#first Quick Summary

Graphic representation of the "grep" method in Ruby's "Enumerable" module

In the simplest possible terms Which items in the collection are a === match for a given value?
Ruby version 1.8 and 1.9
Expects
  • An argument against which every object in the collection will be compared using the === operator.
  • (Optional) A block to be used in a map operation on the resulting array.
Returns
  • If no block is given, an array containing the items in the collection that were a === for the given argument.
  • If a block is given, an array containing the items in the collection that were a === for the given argument, which is then mapped using the block.
RubyDoc.org’s entry Enumerable#grep

Enumerable#grep, Regular Expressions and Arrays

The grep method’s name implies regular expressions, and that’s one of its uses. When given a regular expression as an argument and used without a block, grep returns an array containing the items in the original array that match the given regular expression.

# Here's a list of countries, some of them with "stan" in their names.
#
# I'm including Stan Lee, creator of many wonderful superhero comics simply because
# he's cool enough to be his own country.
countries = ["Afghanistan", "Burkina Faso", "Kazakhstan", "France", "Tajikistan",
"Iceland", "Uzbekistan", "Australia", "Stan Lee"]
=> ["Afghanistan", "Burkina Faso", "Kazakhstan", "France", "Tajikistan",
"Iceland", "Uzbekistan", "Australia", "Stan Lee"]

# Which countries have the string "stan" in their names?
countries.grep(/stan/)
=> ["Afghanistan", "Kazakhstan", "Tajikistan", "Uzbekistan"]

# Note that "Stan Lee" wasn't included in that list. "Stan" and "stan" aren't the
# same thing, but that's easy to fix:
countries.grep(/[S|s]tan/)
=> ["Afghanistan", "Kazakhstan", "Tajikistan", "Uzbekistan", "Stan Lee"]

When a block is used with grep, the contents of the result array are passed through the block and the resulting array is returned. Think of it as grep followed by a collect/map operation.

# Let's get a look at those countries with "Stan" and "stan" in their names again:
countries.grep(/[S|s]tan/)
=> ["Afghanistan", "Kazakhstan", "Tajikistan", "Uzbekistan", "Stan Lee"]

# Let's get the lengths of the names of those countries:
countries.grep(/[S|s]tan/) {|country| country.length}
=> [11, 10, 10, 10, 8]

# It's a slightly shorter version of this:
countries.grep(/[S|s]tan/).map {|country| country.length}
=> [11, 10, 10, 10, 8]

# This time, let's find all the "stans" and uppercase them
countries.grep(/[S|s]tan/) {|country| country.upcase}
=> ["AFGHANISTAN", "KAZAKHSTAN", "TAJIKISTAN", "UZBEKISTAN", "STAN LEE"]

# And here's the version that uses map:
countries.grep(/[S|s]tan/).map {|country| country.upcase}
=> ["AFGHANISTAN", "KAZAKHSTAN", "TAJIKISTAN", "UZBEKISTAN", "STAN LEE"]

What Enumerable#grep Really Does: The === Operator

Here’s grep‘s secret: what it actually does is take each item in the array, compares it against the given argument using Ruby’s === (the “triple equals”) operator and returns an array of those items in the original array for which the comparison returns true.

For regular expressions, the === operator is grep-like. The expression r === s operator returns true if there is a match for regular expression r in string s.

Different classes implement === differently. For example, in the Range class, === is used to see if an item is within the range. The expression r === x returns true if x is in range r. Here’s grep in action when its argument is a range:

# These are the years when the band Radiohead released an album
radiohead_album_years = [1993, 1995, 1997, 2000, 2003, 2007]
=> [1993, 1995, 1997, 2000, 2003, 2007]

# And these are the years when Radiohead released an album between 1996 and
# 2002 inclusive
radiohead_album_years.grep((1996..2002))
=> [1997, 2000]

Generally speaking, collection.grep(thing_to_compare) compares thing_to_compare with each item in collection using the === operator as defined for thing_to_compare‘s class. It returns an array of those items in the original array for which the comparison returned true.

Don’t forget the extra processing — a map operation — comes “free” if you provide grep with a block:

radiohead_album_years = [1993, 1995, 1997, 2000, 2003, 2007]
=> [1993, 1995, 1997, 2000, 2003, 2007]

# Adding a block performs a map operation on grep's initial results
radiohead_album_years.grep((1996..2002)) {|year| year % 2 == 1 ? "odd" : "even" }
=> ["odd", "even"]

Enumerable#grep and Hashes

I’ll put it simply: Enumerable#grep isn’t terribly useful with hashes. Like most methods of Enumerable, when applied to a hash, grep, as it iterates through the hash, converts each key-value pair into a two-element array where the first element is the key and the second element is the corresponding value.

As I mentioned earlier, grep uses the === operator to do its comparison, and for arrays, === returns true only when comparing identical arrays:

# Identical arrays
[1, 2] === [1, 2]
=> true

# How about the first array as a subset of the second?
[1] === [1, 2]
=> false

# How about the first array as a superset of the second?
[1, 2, 3] === [1, 2]
=> false

# How about one array as a permutation of the other?
[2, 1] === [1, 2]
=> false

The practical upshot of all this is that for hashes, grep will return the empty array [] for most arguments, with the notable exception of an argument that is a two-dimensional array that corresponds to one of the key-value pairs in the hash.

That was a bit wordy, but an example should clear things right up:

# These are countries and their total areas (not counting outside territories)
# in square kilometres.
total_country_areas = {"Afghanistan"  => 647_500,
                       "Burkina Faso" => 274_200,
                       "Kazakhstan"   => 2_717_300,
                       "France"       => 547_030}
=> {"Afghanistan"=>647500, "Burkina Faso"=>274200, "Kazakhstan"=>2717300, "France"=>547030}

# Is there a '"Burkina Faso" => 274200' item in the hash?
total_country_areas.grep(["Burkina Faso", 274_200])
=> [["Burkina Faso", 274200]]

# That worked because the array argument we provided was an exact match
# for one of the items in the hash when it is converted into an array.

# Is there a '"Burkina Faso" => 0' item in the hash?
total_country_areas.grep(["Burkina Faso", 0])
=> []

# That didn't work because the array argument didn't correspond to any of the items
# in the hash.

Making Hashes grep-able

If you need to find which keys in a hatch pattern-match a given value, use the Hash#keys method (which returns an array of the hash’s keys) and grep that:

# Again with the countries and the areas...
total_country_areas = {"Afghanistan"  => 647_500,
                       "Burkina Faso" => 274_200,
                       "Kazakhstan"   => 2_717_300,
                       "France"       => 547_030}
=> {"Afghanistan"=>647500, "Burkina Faso"=>274200, "Kazakhstan"=>2717300, "France"=>547030}

# Which ones are the "stans"?
total_country_areas.keys.grep(/stan/)
=> ["Afghanistan", "Kazakhstan"]

If you need to-find which values in a hatch pattern-match a given value, use the Hash#values method (which returns an array of the hash’s values) and grep that:

# Of the countries' total areas, which the ones between
# 500,000 and 1 million square km?
total_country_areas.values.grep((500_000..1_000_000))
=> [647500, 547030]

What if you want to find key-value pairs where either the key or the value is a === match for a given argument? There’s a way to do that, and I’ll cover it when we get to the Enumerable#inject method. It’ll be soon, I promise!

Categories
Uncategorized

What are Your Favorite Software Synths, Samplers and Sound Modules?

M-Audio Axiom 25 USB MIDI keyboard
My toy: M-Audio Axiom 25 USB MIDI keyboard

For my 40th birthday, the Ginger Ninja got me something I’d had my eye on for some time: a USB MIDI keyboard, specifically an M-Audio Axiom 25, a nice little unit with a lot of features. Prior to my picking up the accordion and getting the “Accordion Guy” nickname, I was a synth player for a good long time. I’ve been meaning to get back into it.

I still have a couple of old hardware synths: a Korg Wavestation A/D (a rackmount unit version of the Korg Wavestation) from my days at Crazy Go Nuts University and a Korg Poly-800 that my friend Steph gave to me when she moved out of town.

My last experience was software synths wasn’t all that hot: it was in the late 1990s, when computers and networking were a great deal slower. Software synths felt very “laggy” in comparison to my good ol’ reliable hardware, and after noodling with them for a while, I decided that I’d give technology some time to play catch-up. That time has come, and I’d like to ask any of you who are familiar with this stuff: what are your favorite software synths, samplers and sound modules?

I’m looking for a couple of things in software form:

  • A nice, decent general purpose synth/sampler. I expect I’ll be doing more sequencing than live performance, but you never know…
  • A “groove builder” or “Groovebox” in the spirit of the Roland MC-303

I’m currently on a PC laptop (running Ubuntu and when absolutely necessary, Vista), but I expect to buy a Macbook Pro sometime in the near future. I’d like to hear about what’s available for any platform. Let me know in the comments!

Categories
Uncategorized

The Way Computers Were in the Seventies

Inspired by my earlier post on the Accordion Guy blog titled The Way Movies Were in the Seventies, I present to you this image showing the way computers were in the seventies:

The way computers were in the seventies: "A small digital computer designed for the businessman" and "a large computer installation"
Illustrations courtesy of Miss Fipi Lele.

Categories
Uncategorized

Great Showdowns (of the 8-bit Era)

Can you identify the ’80s-era games depicted in Scott Campbell’s piece, Great Showdowns (of the 8-bit Era)?

Great showdowns of the 8-bit era

Categories
Uncategorized

My Stack of Old Computer Books

While cleaning out my home office, I found a box books that I’ve been hanging on to for historical purposes and sentimental reasons.

First, this collection of Apple ][ manuals, back from when I had my first computer, an Apple //e. These manuals came with the original apple ][; my //e manuals must be kicking around somewhere…

Apple ][ Manuals

And from my university days, these books: the Adele Goldberg Smalltalk-80 series, Computer Systems in Business, which is rather quaint when read with today’s eyes, and Inside Macintosh from the System 7/8 era:

Smalltalk-80 books, "Computer Systems in Business", Inside Macintosh books

I know I’ve got Lubomir Bic’s The Logical Design of Operating Systems — from which I learned concurrent programming — stashed away, but I can’t seem to find it at the moment.

Categories
Uncategorized

Pics from the Office

I was inspired by yesterday’s posting of the office space used by people developing the Boeing 787 Dreamliner to post photos of b5media’s tech team office. This is the old b5media office; the rest of the team — operations, content, marketing and advertising — are in an office across the hall.

The space is looking pretty zen right now, but I kind of like it. We’ll fill it up eventually.

You can click any of the thumbnails below to see the full-size photo:

Categories
Uncategorized

Enumerating Enumerable: Enumerable#first

Enumerating Enumerable

Welcome to another installment of Enumerating Enumerable, my series of articles in I attempt to do a better job of documenting Ruby’s Enumerable module than Ruby-Doc.org. In this installment, I cover the first method.

In case you missed any of the previous articles, they’re listed and linked below:

  1. all?
  2. any?
  3. collect / map
  4. count
  5. cycle
  6. detect / find
  7. drop
  8. drop_while
  9. each_cons
  10. each_slice
  11. each_with_index
  12. entries / to_a
  13. find_all / select
  14. find_index

Enumerable#first Quick Summary

Graphic representing the "first" method in Ruby's "Enumerable" module

In the simplest possible terms What are the first n items in the collection?
Ruby version 1.8 and 1.9
Expects An optional integer n that specifies the first n items of the collection to return. If this integer is not given, n is 1 by default.
Returns If first is applied to a collection containing m elements:

  • The first item in the collection, if m > 0 and no argument n is provided.
  • An array containing the first n items in the collection, if m > 0 and an argument n is provided.
  • nil if the collection is empty and no argument n is provided.
  • The empty array [] if the collection is empty and an argument n is provided.
RubyDoc.org’s entry Enumerable#first

Enumerable#first and Arrays

When used on an array without an argument, first returns the first item in the array:

posts = ["First post!", "Second post!", "Third post!"]
=> ["First post!", "Second post!", "Third post!"]

# What's the first item in posts?
posts.first
=> "First post!"

# Here's the equivalent using array notation:
posts[0]
=> "First post!"

When used on an array with an integer argument n, first returns an array containing the first n items in the original array:

# What are the first 2 items in posts?
posts.first 2
=> ["First post!", "Second post!"]

# Note that when you provide an argument of 1,
# the result is still an array -- with just one element.
# If you want a scalar, don't use an argument.
posts.first 1
=> ["First post!"]

# Here's the equivalent using array slice notation:
posts[0..1]
=> ["First post!", "Second post!"]

posts[0...2]
=> ["First post!", "Second post!"]

When used on an empty array, first returns:

  • nil if no argument n is provided
  • The empty array, [], if an argument n is provided

[].first
=> nil

[].first 2
=> []

Enumerable#first and Hashes

In Ruby 1.8 and previous versions, hash order is seemingly arbitrary. Starting with Ruby 1.9, hashes retain the order in which they were defined, which makes the first method a little more applicable.

When used on a hash without an argument, first returns the first item in the hash as a two-element array, with the key as the first element and the corresponding value as the second element.

# Let's see what stages of partying our friends are in
party_stages = {"Alice" => :party_mineral,
                "Bob"   => :party_animal,
                "Carol" => :party_reptile,
                "Dave"  => :party_vegetable}
=> {"Alice"=>:party_mineral, "Bob"=>:party_animal, "Carol"=>:party_reptile, "Dave"=>:party_vegetable}

# Who's the first partier and what state is s/he in?
party_stages.first
=> ["Alice", :party_mineral]

When used on a hash with an integer argument n, first returns an array containing the first n items in the hash, with each item represented as a two-element array:

party_stages.first 2
=> [["Alice", :party_mineral], ["Bob", :party_animal]]

# Note that when you provide an argument of 1,
# the result is still an array -- with just one element.
# If you want a scalar, don't use an argument.
party_stages.first 1
=> [["Alice", :party_mineral]]

When used on an empty hash, first returns:

  • nil if no argument n is provided
  • The empty array, [], if an argument n is provided

{}.first
=> nil

{}.first 2
=> []