# Code too hashy, I think

**URL:** <https://rubytalk.org/t/code-too-hashy-i-think/36516>\
**Category:** ruby-talk\
**Created:** [28 March 2007 17:31 UTC](https://rubytalk.org/t/code-too-hashy-i-think/36516 "2007-03-28T17:31:43Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![Giles\_Bowkett](https://avatars.discourse-cdn.com/v4/letter/g/96bed5/32.png) [@Giles\_Bowkett](https://rubytalk.org/u/Giles_Bowkett)\
**Post date:** [28 March 2007 17:31 UTC](https://rubytalk.org/t/code-too-hashy-i-think/36516/1 "2007-03-28T17:31:43Z")

</div>

I came to Ruby from a scattering of Java, a tiny bit of Python, and a  
ton of Perl. So the other day I wrote a simple utility script and  
afterwards realized it may have been very influenced by all those  
years of Perl. Specifically, it seemed to use hashes too much.

How can I cure myself of my hash addiction? 😉

Seriously -- I had a CSV file from an Excel spreadsheet. Each row  
represented a thing, so I made a Struct for that thing. Those things  
were in groups, so I hashed them by their common feature, a unique id  
from the spreadsheet. But the last character in the unique id on the  
spreadsheet was non-unique, and had to be preserved. Each group had to  
have a dash-delimited list of those characters, relevant to that  
particular group (since different groups would have different terminal  
characters in their unique ids). So I hashed them again -- and that's  
what seemed like overkill.

What's the most idiomatic Ruby data structure? Would another Struct  
have been more maintainable? The code was perfectly functional, and  
it's pretty readable, but you can read it and go, oh, this is a  
recovering Perl hacker. I picked it up from another programmer I work  
with, and looking over what he had initially, I was able to go, oh,  
this is a recovering PHP hacker. I want my code to look like, oh, this  
is a Ruby hacker. How do I hide my shameful past?

> **···**
>
> --  
> Giles Bowkett  
> [http://www.gilesgoatboy.org](http://www.gilesgoatboy.org)
> 
> > **[Giles Bowkett](http://gilesbowkett.blogspot.com)**
> >
> > half-disavowed old blog. new blog at gilesbowkett.com
> 
>   
> 
> > **[Wixel](https://giles.tumblr.com/#_=_)**
> >
> > I am free, That is why i'm Lost.

---

<div class="post-metadata">

**Author:** ![Andrew\_Libby](https://avatars.discourse-cdn.com/v4/letter/a/e274bd/32.png) [@Andrew\_Libby](https://rubytalk.org/u/Andrew_Libby)\
**Post date:** [28 March 2007 18:47 UTC](https://rubytalk.org/t/code-too-hashy-i-think/36516/2 "2007-03-28T18:47:04Z")

</div>

Hi Giles,

I'm a new ruby convert (from primarily Perl, but also Java and PHP  
myself). I'd like to offer my observation and see if other more  
experienced Ruby programmers have input.

To risk sounding trite, my take on the most idiomatic Ruby data  
structure would be the class. When I deal with CSVs I typically  
use the CSV object in the standard library (though I've read there  
may be better ways) and do something like the code below.

At the end of the day, it's a hash cloaked in object clothing. I  
use the first line of the CSV to determine the names of the  
keys in the hash (and hence the instance method names for the  
object instance for each row).

The reason I take this approach is that it avoids locking you to  
the hash syntax using or fetch/ store. Additionally, it would  
allow you to subclass and have instance methods like:

def full\_name  
&nbsp;&nbsp;first + " " + last  
end

I'm still learning ruby, so feed back on the approach is welcome.

#!/usr/bin/ruby

require 'csv'

class ObjectCsvParser  
&nbsp;&nbsp;&nbsp;&nbsp;attr :attributes

&nbsp;&nbsp;&nbsp;&nbsp;def initialize(fields,values)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@attributes = Hash[  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\*[  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(0..fields.length-1).map {  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\>i\> [fields[i], values[i]]  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;].flatten  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;]

&nbsp;&nbsp;&nbsp;&nbsp;end

&nbsp;&nbsp;&nbsp;&nbsp;def method\_missing(method\_name)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(@attributes[method\_name])  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@attributes[method\_name]  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;raise NoMethodError.new(method\_name)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;end

&nbsp;&nbsp;&nbsp;&nbsp;def self.each\_record(fn,&block)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fields = nil  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CSV.open(fn,'r') do |line|  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(fields == nil)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fields = line.map { |l| l.downcase.to\_sym }  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;next  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;yield ObjectCsvParser.new(fields,line)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;end  
end

# Assuming your CSV has last, first, and email as fields  
ObjectCsvParser.each\_record(ARGV.shift) do |record|  
&nbsp;&nbsp;&nbsp;&nbsp;puts "Last: " + record.last  
&nbsp;&nbsp;&nbsp;&nbsp;puts "First: " + record.first  
&nbsp;&nbsp;&nbsp;&nbsp;puts "Email: " + record.email  
end

Cheers!

Andy

Giles Bowkett wrote:

> **···**
>
> > I came to Ruby from a scattering of Java, a tiny bit of Python, and a  
> > ton of Perl. So the other day I wrote a simple utility script and  
> > afterwards realized it may have been very influenced by all those  
> > years of Perl. Specifically, it seemed to use hashes too much.
> > 
> > How can I cure myself of my hash addiction? 😉
> > 
> > Seriously -- I had a CSV file from an Excel spreadsheet. Each row  
> > represented a thing, so I made a Struct for that thing. Those things  
> > were in groups, so I hashed them by their common feature, a unique id  
> > from the spreadsheet. But the last character in the unique id on the  
> > spreadsheet was non-unique, and had to be preserved. Each group had to  
> > have a dash-delimited list of those characters, relevant to that  
> > particular group (since different groups would have different terminal  
> > characters in their unique ids). So I hashed them again -- and that's  
> > what seemed like overkill.
> > 
> > What's the most idiomatic Ruby data structure? Would another Struct  
> > have been more maintainable? The code was perfectly functional, and  
> > it's pretty readable, but you can read it and go, oh, this is a  
> > recovering Perl hacker. I picked it up from another programmer I work  
> > with, and looking over what he had initially, I was able to go, oh,  
> > this is a recovering PHP hacker. I want my code to look like, oh, this  
> > is a Ruby hacker. How do I hide my shameful past?
> 
> --  
> Andrew Libby  
> Tangeis, LLC  
> Innovative IT Management Solutions  
> alibby@tangeis.com

---

<div class="post-metadata">

**Author:** ![Brian\_Candler](https://avatars.discourse-cdn.com/v4/letter/b/5f9b8f/32.png) [@Brian\_Candler](https://rubytalk.org/u/Brian_Candler)\
**Post date:** [28 March 2007 19:14 UTC](https://rubytalk.org/t/code-too-hashy-i-think/36516/3 "2007-03-28T19:14:39Z")

</div>

Perhaps you want Struct or OpenStruct (both in the standard install; for the  
latter you will need to require 'ostruct.rb')

From /usr/lib/ruby/1.8/ostruct.rb:

# OpenStruct allows you to create data objects and set arbitrary attributes.  
# For example:

> **···**
>
> On Thu, Mar 29, 2007 at 03:47:04AM +0900, Andrew Libby wrote:
> 
> > At the end of the day, it's a hash cloaked in object clothing.
> 
> #  
> # require 'ostruct'  
> #  
> # record = OpenStruct.new  
> # record.name = "John Smith"  
> # record.age = 70  
> # record.pension = 300  
> #  
> # puts record.name # -\> "John Smith"  
> # puts record.address # -\> nil  
> #  
> # It is like a hash with a different way to access the data. In fact, it is  
> # implemented with a hash, and you can initialize it with one.  
> #  
> # hash = { "country" =\> "Australia", :population =\> 20\_000\_000 }  
> # data = OpenStruct.new(hash)  
> #  
> # p data # -\> \<OpenStruct country="Australia" population=20000000\>

---

<div class="post-metadata">

**Author:** ![Andrew\_Libby](https://avatars.discourse-cdn.com/v4/letter/a/e274bd/32.png) [@Andrew\_Libby](https://rubytalk.org/u/Andrew_Libby)\
**Post date:** [28 March 2007 19:45 UTC](https://rubytalk.org/t/code-too-hashy-i-think/36516/4 "2007-03-28T19:45:37Z")

</div>

Nice! That's great Brian, I love it. A quick  
fix to the code I posted previously makes use of  
this class. My class extends OpenStruct, and no longer  
has an @attributes attribute, or a method\_missing  
method.

Thanks!

#!/usr/bin/ruby

require 'csv'  
require 'ostruct'

class ObjectCsvParser \< OpenStruct  
&nbsp;&nbsp;&nbsp;&nbsp;def initialize(fields,values)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;super Hash[  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\*[  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(0..fields.length-1).map {  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\>i\> [fields[i], values[i]]  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;].flatten  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;]

&nbsp;&nbsp;&nbsp;&nbsp;end

&nbsp;&nbsp;&nbsp;&nbsp;def self.each\_record(fn,&block)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fields = nil  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CSV.open(fn,'r') do |line|  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(fields == nil)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fields = line.map { |l| l.downcase.to\_sym }  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;next  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;yield ObjectCsvParser.new(fields,line)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;end  
end

# Assuming your CSV has last, first, and email as fields  
ObjectCsvParser.each\_record(ARGV.shift) do |record|  
&nbsp;&nbsp;&nbsp;&nbsp;puts "Last: " + record.last  
&nbsp;&nbsp;&nbsp;&nbsp;puts "First: " + record.first  
&nbsp;&nbsp;&nbsp;&nbsp;puts "Email: " + record.email  
end

Brian Candler wrote:

> **···**
>
> > On Thu, Mar 29, 2007 at 03:47:04AM +0900, Andrew Libby wrote:
> > 
> > > At the end of the day, it's a hash cloaked in object clothing.
> > 
> > Perhaps you want Struct or OpenStruct (both in the standard install; for the  
> > latter you will need to require 'ostruct.rb')
> > 
> > From /usr/lib/ruby/1.8/ostruct.rb:
> > 
> > # OpenStruct allows you to create data objects and set arbitrary attributes.  
> > # For example:  
> > #  
> > # require 'ostruct'  
> > #  
> > # record = OpenStruct.new  
> > # record.name = "John Smith"  
> > # record.age = 70  
> > # record.pension = 300  
> > #  
> > # puts record.name # -\> "John Smith"  
> > # puts record.address # -\> nil  
> > #  
> > # It is like a hash with a different way to access the data. In fact, it is  
> > # implemented with a hash, and you can initialize it with one.  
> > #  
> > # hash = { "country" =\> "Australia", :population =\> 20\_000\_000 }  
> > # data = OpenStruct.new(hash)  
> > #  
> > # p data # -\> \<OpenStruct country="Australia" population=20000000\>
> 
> --  
> Andrew Libby  
> Tangeis, LLC  
> Innovative IT Management Solutions  
> alibby@tangeis.com

---

<div class="post-metadata">

**Author:** ![Brian\_Candler](https://avatars.discourse-cdn.com/v4/letter/b/5f9b8f/32.png) [@Brian\_Candler](https://rubytalk.org/u/Brian_Candler)\
**Post date:** [28 March 2007 20:02 UTC](https://rubytalk.org/t/code-too-hashy-i-think/36516/5 "2007-03-28T20:02:09Z")

</div>

NP. Depending on how dynamic you want to be, it's smaller with Struct:

#!/usr/bin/ruby

require 'csv'

class ObjectCsvParser  
&nbsp;&nbsp;&nbsp;&nbsp;def self.each\_record(fn,&block)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;klass = nil  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CSV.open(fn,'r') do |line|  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if klass.nil?  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;klass = Struct.new( \*line.map { |l| l.downcase.to\_sym } )  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;next  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;yield klass.new(\*line)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;end  
end

# Assuming your CSV has last, first, and email as fields  
ObjectCsvParser.each\_record(ARGV.shift) do |record|  
&nbsp;&nbsp;&nbsp;&nbsp;puts "Last: " + record.last  
&nbsp;&nbsp;&nbsp;&nbsp;puts "First: " + record.first  
&nbsp;&nbsp;&nbsp;&nbsp;puts "Email: " + record.email  
end

> **···**
>
> On Thu, Mar 29, 2007 at 04:45:37AM +0900, Andrew Libby wrote:
> 
> > Nice! That's great Brian, I love it. A quick  
> > fix to the code I posted previously makes use of  
> > this class. My class extends OpenStruct, and no longer  
> > has an @attributes attribute, or a method\_missing  
> > method.
> > 
> > Thanks!

---

<div class="post-metadata">

**Author:** ![Giles\_Bowkett](https://avatars.discourse-cdn.com/v4/letter/g/96bed5/32.png) [@Giles\_Bowkett](https://rubytalk.org/u/Giles_Bowkett)\
**Post date:** [28 March 2007 22:01 UTC](https://rubytalk.org/t/code-too-hashy-i-think/36516/6 "2007-03-28T22:01:39Z")

</div>

Both good solutions. My own approach mostly revolved around Struct,  
I'd heard of both CSV and OpenStruct but I was coding in a hurry so I  
didn't think to use them.

Thing is, there were elements on each line which affected not the  
lines themselves but the groups those lines were part of, and to  
collect those, I resorted to an additional hash. So I ended up with a  
hash of Structs, indexed by group ID, and a hash of collected  
elements, also indexed by group ID. I should have probably just made a  
multidimensional hash, but even that seems Perl-y. I think the real  
thing to do would have been to create another Struct for the groups,  
containing both an array of Structs -- one for each line in the group  
-- and the collected-data string as well. That might have been better.

> **···**
>
> --  
> Giles Bowkett  
> [http://www.gilesgoatboy.org](http://www.gilesgoatboy.org)
> 
> > **[Giles Bowkett](http://gilesbowkett.blogspot.com)**
> >
> > never not correct, except sometimes
> 
>   
> [http://giles.tumblr.com/](http://giles.tumblr.com/)

---

<div class="post-metadata">

**Author:** ![James\_Edward\_Gray\_II](https://avatars.discourse-cdn.com/v4/letter/j/ea5d25/32.png) [@James\_Edward\_Gray\_II](https://rubytalk.org/u/James_Edward_Gray_II)\
**Post date:** [28 March 2007 22:09 UTC](https://rubytalk.org/t/code-too-hashy-i-think/36516/7 "2007-03-28T22:09:42Z")

</div>

Any chance you could show us some trivial example data (just ten lines or so is fine and we only need the key fields) and how you want to access it. We might have better ideas when we see the specifics...

James Edward Gray II

> **···**
>
> On Mar 28, 2007, at 5:01 PM, Giles Bowkett wrote:
> 
> > Thing is, there were elements on each line which affected not the  
> > lines themselves but the groups those lines were part of, and to  
> > collect those, I resorted to an additional hash. So I ended up with a  
> > hash of Structs, indexed by group ID, and a hash of collected  
> > elements, also indexed by group ID.

---

<div class="post-metadata">

**Author:** ![Giles\_Bowkett](https://avatars.discourse-cdn.com/v4/letter/g/96bed5/32.png) [@Giles\_Bowkett](https://rubytalk.org/u/Giles_Bowkett)\
**Post date:** [29 March 2007 00:54 UTC](https://rubytalk.org/t/code-too-hashy-i-think/36516/8 "2007-03-29T00:54:03Z")

</div>

> \> Thing is, there were elements on each line which affected not the  
> \> lines themselves but the groups those lines were part of, and to  
> \> collect those, I resorted to an additional hash. So I ended up with a  
> \> hash of Structs, indexed by group ID, and a hash of collected  
> \> elements, also indexed by group ID.
> 
> Any chance you could show us some trivial example data (just ten  
> lines or so is fine and we only need the key fields) and how you want  
> to access it. We might have better ideas when we see the specifics...

I think there's no harm in that. Should be able to this evening.

Since starting this thread, I've looked at another developer's code  
and seen very plainly that they were writing Python before they  
started writing Ruby. It'd be nice to make my Ruby so idiomatic that  
people didn't believe me when I told them I knew other languages. Kind  
of like learning to speak a foreign language with a perfect accent.

> **···**
>
> --  
> Giles Bowkett  
> [http://www.gilesgoatboy.org](http://www.gilesgoatboy.org)
> 
> > **[Giles Bowkett](http://gilesbowkett.blogspot.com)**
> >
> > half-disavowed old blog. new blog at gilesbowkett.com
> 
> [http://giles.tumblr.com/](http://giles.tumblr.com/)

---

<div class="post-metadata">

**Author:** ![Giles\_Bowkett](https://avatars.discourse-cdn.com/v4/letter/g/96bed5/32.png) [@Giles\_Bowkett](https://rubytalk.org/u/Giles_Bowkett)\
**Post date:** [29 March 2007 21:44 UTC](https://rubytalk.org/t/code-too-hashy-i-think/36516/9 "2007-03-29T21:44:02Z")

</div>

> Any chance you could show us some trivial example data (just ten  
> lines or so is fine and we only need the key fields) and how you want  
> to access it. We might have better ideas when we see the specifics...

OK, here's sample data and the script. I changed unique ID numbers and  
made some subtle text changes as well to prevent the data from being  
an NDA violation.

[http://gilesbowkett.com/blog\_code\_samples/muppet.csv](http://gilesbowkett.com/blog_code_samples/muppet.csv)  
[http://gilesbowkett.com/blog\_code\_samples/muppetimport.rb](http://gilesbowkett.com/blog_code_samples/muppetimport.rb)

You can probably actually run this code with only a few modifications;  
namely, there's stuff which expects Rails models to be defined, you  
can comment that out and uncomment the "# reporting!" code, and you're  
good to go.

(This was a quick script, done in a hurry, so it's not the best thing  
I've ever done.)

> **···**
>
> --  
> Giles Bowkett  
> [http://www.gilesgoatboy.org](http://www.gilesgoatboy.org)
> 
> > **[Giles Bowkett](http://gilesbowkett.blogspot.com)**
> >
> > half-disavowed old blog. new blog at gilesbowkett.com
> 
> [http://giles.tumblr.com/](http://giles.tumblr.com/)

---

<div class="post-metadata">

**Author:** ![Pat\_Maddox1](https://avatars.discourse-cdn.com/v4/letter/p/ccd318/32.png) [@Pat\_Maddox1](https://rubytalk.org/u/Pat_Maddox1)\
**Post date:** [29 March 2007 06:36 UTC](https://rubytalk.org/t/code-too-hashy-i-think/36516/10 "2007-03-29T06:36:57Z")

</div>

My Ruby is super sexy. Just thought I'd throw that in there. If you  
want to form a shrine for me, I won't object.

Pat

> **···**
>
> On 3/28/07, Giles Bowkett \<gilesb@gmail.com\> wrote:
> 
> > \> \> Thing is, there were elements on each line which affected not the  
> > \> \> lines themselves but the groups those lines were part of, and to  
> > \> \> collect those, I resorted to an additional hash. So I ended up with a  
> > \> \> hash of Structs, indexed by group ID, and a hash of collected  
> > \> \> elements, also indexed by group ID.  
> > \>  
> > \> Any chance you could show us some trivial example data (just ten  
> > \> lines or so is fine and we only need the key fields) and how you want  
> > \> to access it. We might have better ideas when we see the specifics...
> > 
> > I think there's no harm in that. Should be able to this evening.
> > 
> > Since starting this thread, I've looked at another developer's code  
> > and seen very plainly that they were writing Python before they  
> > started writing Ruby. It'd be nice to make my Ruby so idiomatic that  
> > people didn't believe me when I told them I knew other languages. Kind  
> > of like learning to speak a foreign language with a perfect accent.

---

<div class="post-metadata">

**Author:** ![James\_Edward\_Gray\_II](https://avatars.discourse-cdn.com/v4/letter/j/ea5d25/32.png) [@James\_Edward\_Gray\_II](https://rubytalk.org/u/James_Edward_Gray_II)\
**Post date:** [30 March 2007 00:58 UTC](https://rubytalk.org/t/code-too-hashy-i-think/36516/11 "2007-03-30T00:58:16Z")

</div>

Usually we approach these problems with iterators.

First I show some ways you might select subsets of data. This isn't as fast as Hash based access, but can be useful when you need to be able to view the data several different ways.

If you still need the Hash indexes, I show how I would go about building those next.

My hope is that something in here will give you some fresh ideas:

#!/usr/bin/env ruby -w

require "pp"

$/ = "\r" # switch to the unusual line endings

# read in the data  
Stuff = Struct.new(:family, :description, :color, :size\_code, :sku)  
all\_stuff = ARGF.inject(Array.new) do |rows, row|  
&nbsp;&nbsp;&nbsp;next rows unless row =~ /\S/  
&nbsp;&nbsp;&nbsp;rows.push(Stuff.new(\*row.split(/\s\*,\s\*/)[0..4]))  
end

# find all by an sku when needed  
pp all\_stuff.select { |s| s.sku.include? "35860466" }  
puts

# find all entries of a certain size  
pp all\_stuff.select { |s| s.size\_code == "M" }  
puts

# or group the data by size  
by\_size = all\_stuff.inject(Hash.new { |size, a| size[a] = }) do |grouped, s|  
&nbsp;&nbsp;&nbsp;grouped[s.size\_code] \<\< s  
&nbsp;&nbsp;&nbsp;grouped  
end  
pp by\_size

\_\_END\_\_

Hope that helps.

James Edward Gray II

> **···**
>
> On Mar 29, 2007, at 4:44 PM, Giles Bowkett wrote:
> 
> > > Any chance you could show us some trivial example data (just ten  
> > > lines or so is fine and we only need the key fields) and how you want  
> > > to access it. We might have better ideas when we see the specifics...
> > 
> > OK, here's sample data and the script. I changed unique ID numbers and  
> > made some subtle text changes as well to prevent the data from being  
> > an NDA violation.
> > 
> > [http://gilesbowkett.com/blog\_code\_samples/muppet.csv](http://gilesbowkett.com/blog_code_samples/muppet.csv)  
> > [http://gilesbowkett.com/blog\_code\_samples/muppetimport.rb](http://gilesbowkett.com/blog_code_samples/muppetimport.rb)

---

<div class="post-metadata">

**Author:** ![Giles\_Bowkett](https://avatars.discourse-cdn.com/v4/letter/g/96bed5/32.png) [@Giles\_Bowkett](https://rubytalk.org/u/Giles_Bowkett)\
**Post date:** [29 March 2007 07:30 UTC](https://rubytalk.org/t/code-too-hashy-i-think/36516/12 "2007-03-29T07:30:13Z")

</div>

> \> Since starting this thread, I've looked at another developer's code  
> \> and seen very plainly that they were writing Python before they  
> \> started writing Ruby. It'd be nice to make my Ruby so idiomatic that  
> \> people didn't believe me when I told them I knew other languages. Kind  
> \> of like learning to speak a foreign language with a perfect accent.
> 
> My Ruby is super sexy. Just thought I'd throw that in there. If you  
> want to form a shrine for me, I won't object.

Thank you, Pat. I'll keep that in mind.

> **···**
>
> --  
> Giles Bowkett  
> [http://www.gilesgoatboy.org](http://www.gilesgoatboy.org)
> 
> > **[Giles Bowkett](http://gilesbowkett.blogspot.com)**
> >
> > half-disavowed old blog. new blog at gilesbowkett.com
> 
> [http://giles.tumblr.com/](http://giles.tumblr.com/)

---

<div class="post-metadata">

**Author:** ![Gary\_Wright](https://avatars.discourse-cdn.com/v4/letter/g/58956e/32.png) [@Gary\_Wright](https://rubytalk.org/u/Gary_Wright)\
**Post date:** [30 March 2007 01:27 UTC](https://rubytalk.org/t/code-too-hashy-i-think/36516/13 "2007-03-30T01:27:02Z")

</div>

Set has a nice method, classify, that can help with this if you aren't  
concerned with duplicates.

require 'set'

by\_size = all\_stuff.to\_set.classify { |s| s.size\_code }

I'm surprised classify isn't part of Enumerable. It is a generalization of  
Enumerable#partition.

Gary Wright

> **···**
>
> On Mar 29, 2007, at 8:58 PM, James Edward Gray II wrote:
> 
> > # or group the data by size  
> > by\_size = all\_stuff.inject(Hash.new { |size, a| size[a] = }) do |grouped, s|  
> > &nbsp;&nbsp;grouped[s.size\_code] \<\< s  
> > &nbsp;&nbsp;grouped  
> > end  
> > pp by\_size
