In Progress
Unit 1, Lesson 1
In Progress

Hash Subset

Video transcript & code

Lately I've been going hiking a lot. When hiking deep in the woods, it's important to be prepared beforehand with the right tools and supplies.

So I have a checklist.

GEAR = {
  water: false,
  snacks: true,
  map: false,
  whistle: true,
}

OK, it's early in the morning, and I'm ready to head out the door and drive into the Smokies. Let me check my gear real quick…

Got my water bottle? Got my map? Good!

require "./gear"

GEAR.include?(:water)
# => true
GEAR.include?(:map)
# => true

A couple hours later, I'm deep in the mountains.

I take a break for some refreshment, and… what? No water?!

OK, I guess I'll check the map to see how much further I have to go without water… wait. No map either???

require "./gear"

GEAR[:water]                # => false
GEAR[:map]                  # => false

It turns out that in my rush, I made a big mistake. I asked my gear list if it includes :water and :whistle. But .include? on a Hash just checks to see if the hash has that key. It doesn't look at the key's value.

I guess I should have checked each of the key values before I left.

GEAR[:water]                    # => false

Or, I could have used a brand-new feature in Ruby 2.3: I could have compared my gear checklist to a subset. Here's a comparison with a subset that only includes the water item.

Notice how we use the "greater than or equal" operator to ask "does this hash on the left contain the hash on the right"?

require "./gear"

GEAR[:water]                    # => false

GEAR >= {water: true}
# => false

That doesn't seem like much of an improvement over just grabbing the value of a key. The difference comes when we want to check for more than one key and value at a time.

For instance, I could assemble a list of "essential" gear in another hash.

Then I could check to make sure all of that gear is accounted for at once.

GEAR[:water]                    # => false

GEAR >= {water: true}
# => false

essentials = {water: true, map: true}

GEAR >= essentials
# => false

Let's check off the needed items.

When we make the comparison again, the result is true. I have my essentials.

GEAR[:map] = true
GEAR[:water] = true

GEAR >= essentials
# => true

So there you go: thanks to the new hash operators in Ruby 2.3, we can check for subsets of hashes very easily. Happy hiking! …um, I mean, hacking!

Responses