From: William James Date: 2006-03-26T20:08:54+09:00 Subject: Re: deciphering poignant guide chapter 4 example john_sips_tea@yahoo.com wrote: > Hi, > > I'm reading through the poignant guide, and am a bit stuck > at the end of chapter 4 > ( http://poignantguide.net/ruby/chapter-4.html ). It's > regarding the kitty_toys example: > > #!/usr/bin/ruby > > kitty_toys = > [:shape => 'sock', :fabric => 'cashmere'] + > [:shape => 'mouse', :fabric => 'calico'] + > [:shape => 'eggroll', :fabric => 'chenille'] > > kitty_toys.sort_by { |toy| toy[:shape] }.each do |toy| > puts "Blixy has a #{ toy[:shape] } made of #{ toy[:fabric] }" > end > > and I've actually got three sticking points with it: > > 1. For one thing, I don't understand the point of the ":shape" > syntax. I don't understand why the author doesn't just write > the string "shape" instead. What exactly is a "Symbol" object > for? > > The poinant guide says it's just "words that look just like > variables". And "Symbols are lightweight strings." But that > doesn't help me much. The PickAxe 2nd ed, in chapter 3 says, > "The construct :artist is an expression that returns a Symbol > object corresponding to artist.", so, I can understand that > (i.e. that there's some Symbol class and we're getting an > instance of it by using that notation), but I'm still not > getting the point... why not just use strings? What does > having "Symbols" buy the programmer? > > 2. Next up, why is > > kitty_toys = > [:shape => 'sock', :fabric => 'cashmere'] + > [:shape => 'mouse', :fabric => 'calico'] + > [:shape => 'eggroll', :fabric => 'chenille'] > > supposed to be shorthand for > > kitty_toys = [ > {:shape => 'sock', :fabric => 'cashmere'}, > {:shape => 'mouse', :fabric => 'calico'}, > {:shape => 'eggroll', :fabric => 'chenille'} > ] > > How does that work? (Hmm... what does adding Arrays > in Ruby mean anyway? In Python it concatenates.) > Why does this shorthand exist? Hmm,.. it doesn't seem > to be saving much finger typing... > > 3. Finally, at the end of that example given in the poignant > guide: > > #!/usr/bin/ruby > > # ... Create kitty_toys as shown above, then > > kitty_toys.sort_by { |toy| toy[:shape] }.each do |toy| > puts "Blixy has a #{ toy[:shape] } made of #{ toy[:fabric] }" > end > > how does that "kitty_toys.sort_by" line work? I believe that > braces and "do ... end" are equivalent, so it looks to me like > there's some kind of "loop-in-a-loop" going on, as in: No, kitty_toys.sort_by { |toy| toy[:shape] } simply produces an array that's sorted by the shape of each toy. Then he iterates through the array and prints each toy. > > # Warning, Python code follows: > for i in range(1, 8): > for j in range(1, 4): > print i, j > > Is there a more verbose way of writing that kitty_toys snippet > to make it a bit more obvious what's going on? I mean, I guess > the sort_by method is probably looking for something to sort > kitty_toys on, and we're telling it to use what it finds in > toy[:shape] for each hash it iterates over, but then, is that > next "each" looping over items in a given hash, or ... gah. I'm > not getting it. :) > > Thanks, > ---John Here's another way: kitty_toys = [ { :shape, 'sock', :fabric, 'cashmere'}, { :shape, 'mouse', :fabric, 'calico'}, { :shape, 'eggroll', :fabric, 'chenille'} ] puts kitty_toys.sort_by { |toy| toy[:shape] }.map { |toy| "Blixy has a #{ toy[:shape] } made of #{ toy[:fabric] }" }