Then I could just iterate through the keys looking
for a match, then use that key to find the associated
proc and call it.
However, I quickly noticed that this is no good. The
order of iteration is unpredictable. So I couldn't
guarantee that (for example) /abcd/ would be tested
before /abc/, and so on.
So yeah, I ended up using an array of arrays. But it
just felt wrong.
Then I could just iterate through the keys looking
for a match, then use that key to find the associated
proc and call it.
However, I quickly noticed that this is no good. The
order of iteration is unpredictable. So I couldn't
guarantee that (for example) /abcd/ would be tested
before /abc/, and so on.
So yeah, I ended up using an array of arrays. But it
just felt wrong.
Hal
That sort of code is what Chuck Moore evolved into Forth. Seriously, though, isn't there a way to do this with a single array? Store the patterns followed by the lambdas in sequence. Find the first index that matches the pattern and take the lambda at [index+1]? Or two parallel arrays? I use two parallel arrays for this sort of thing a lot -- it's easy for me to read, given my FORTRAN background.
Then I could just iterate through the keys looking
for a match, then use that key to find the associated
proc and call it.
However, I quickly noticed that this is no good. The
order of iteration is unpredictable. So I couldn't
guarantee that (for example) /abcd/ would be tested
before /abc/, and so on.
So yeah, I ended up using an array of arrays. But it
just felt wrong.
To me a Hash feels wrong. Why? Because you don't make any use of hash properties for fast lookup. You just iterate in plain order.
It's just such a common idiom in my code I think I should push it into
my little collection of standard extensions to standard objects.
Why is it so common? Nobody wants a script that does very things in a
very different order depending on very small changes.
* You just spend too long explaining to people why this happens.
* Makes sporadic bugs even harder to find (it works for me, but customer is whinging)
* The results tend not to be comparable (can't diff) or repeatable.
John Carter Phone : (64)(3) 358 6639
Tait Electronics Fax : (64)(3) 359 4632
PO Box 1645 Christchurch Email : john.carter@tait.co.nz
New Zealand
Carter's Clarification of Murphy's Law.
"Things only ever go right so that they may go more spectacularly wrong later."
From this principle, all of life and physics may be deduced.
···
On Sun, 13 Aug 2006, Hal Fulton wrote:
There have been numerous occasions when I wanted an
ordered hash, but usually I can't remember to write
them down.
There have been numerous occasions when I wanted an
ordered hash, but usually I can't remember to write
them down.
Here's my latest one[1]:
I had a string with a bunch of tagged "tolerance fields",
e.g., >>1+/-10% 'tag'<< (a mini DSL?). Based on some sort
of distribution function, e.g., uniform or Gaussian,
I generated an array of samples for each tagged field.
A regular hash was a perfect fit,
samples[tag] = [ sample1, sample2, .. ]
*until* another requirement came up: to present the tags
in order of appearance.
Then I could just iterate through the keys looking
for a match, then use that key to find the associated
proc and call it.
However, I quickly noticed that this is no good. The
order of iteration is unpredictable. So I couldn't
guarantee that (for example) /abcd/ would be tested
before /abc/, and so on.
So yeah, I ended up using an array of arrays. But it
just felt wrong.
Hal
Can't you create your own using mixins and including enumerable or
something like that ?
That sort of code is what Chuck Moore evolved into Forth. Seriously, though, isn't there a way to do this with a single array? Store the patterns followed by the lambdas in sequence. Find the first index that matches the pattern and take the lambda at [index+1]? Or two parallel arrays? I use two parallel arrays for this sort of thing a lot -- it's easy for me to read, given my FORTRAN background.
Yes, I could use a single flat array... I could also program
in FORTRAN...
which calls the Proc associated with the matching element.
I'm not too thrilled with its convolutedness, and I'm sure there's a
better way, but I'm pretty sleepy, so this is the best I'm coming up
with right now. As always, you can write a method to hide the gory
details.
def exec_route input
actions.select { |action| action[input] }.first[input].call
end
He *is* making use of a Hash property. He wants the keys to be unique. None of the other solutions shown in this thread have addressed that.
James Edward Gray II
···
On Aug 13, 2006, at 3:25 AM, Robert Klemme wrote:
Hal Fulton wrote:
There have been numerous occasions when I wanted an
ordered hash, but usually I can't remember to write
them down.
Here's just one.
Once I wanted a "dynamic case statement" of sorts.
I wanted to use procs as values in a hash. Something
like:
actions = { /abcd/ => lambda { do_this },
/xyz/ => lambda { do_that },
/abc/ => lambda { other }}
Then I could just iterate through the keys looking
for a match, then use that key to find the associated
proc and call it.
However, I quickly noticed that this is no good. The
order of iteration is unpredictable. So I couldn't
guarantee that (for example) /abcd/ would be tested
before /abc/, and so on.
So yeah, I ended up using an array of arrays. But it
just felt wrong.
To me a Hash feels wrong. Why? Because you don't make any use of hash properties for fast lookup. You just iterate in plain order.
In the case that Hal is talking about, and in the case where
PDF::Writer uses an ordered hash, this would be inappropriate.
Insertion-ordered associations are generally better. I will probably
be modifying PDF::Writer a bit to make it clear that it's using an
ordered association, not an ordered "hash", but it would be useful to
have an ordered association. Maybe we *could* take advantage of a
literal for this:
ordered_assoc = ( 1 => 2, 2 => 3, 'a' => 5 )
Maybe. For Ruby 2.0.
-austin
···
On 8/13/06, John Carter <john.carter@tait.co.nz> wrote:
I've had to deal with this (interestingly, in something that was
*intended* as a DSL). Just add another field to the structure you
store in the hash and have it increment a global sequence number when
you create it. A little clunky but later you can say:
I had a string with a bunch of tagged "tolerance fields",
e.g., >>1+/-10% 'tag'<< (a mini DSL?). Based on some sort
of distribution function, e.g., uniform or Gaussian,
I generated an array of samples for each tagged field.
A regular hash was a perfect fit,
samples[tag] = [ sample1, sample2, .. ]
*until* another requirement came up: to present the tags
in order of appearance.
I had a string with a bunch of tagged "tolerance fields",
e.g., >>1+/-10% 'tag'<< (a mini DSL?). Based on some sort
of distribution function, e.g., uniform or Gaussian,
I generated an array of samples for each tagged field.
A regular hash was a perfect fit,
samples[tag] = [ sample1, sample2, .. ]
*until* another requirement came up: to present the tags
in order of appearance.
>Hal Fulton wrote:
>>Once I wanted a "dynamic case statement" of sorts.
>>I wanted to use procs as values in a hash. Something
>>like:
>> actions = { /abcd/ => lambda { do_this },
>> /xyz/ => lambda { do_that },
>> /abc/ => lambda { other }}
[...]
>To me a Hash feels wrong. Why? Because you don't make any use of
>hash properties for fast lookup. You just iterate in plain order.
He *is* making use of a Hash property. He wants the keys to be
unique. None of the other solutions shown in this thread have
addressed that.
Hal is making the case for *literal* "ordered hashes". The keys will be
unique because he's writing them himself manually. I don't think he wants to
make use of this:
actions = { /a/ => 1, # <--
/b/ => 2, # \
/a/ => 4 # <--+-- why do this in the first place.
}
actions[/a/] # => 4
The way he uses the structure is reminiscent of Array#assoc. The only thing
a Hash has going for it in this case is the cleaner notation and the arrow.
But
actions = ASSOC [/abcd/, lambda{ ... },
/abc/, lambda{ ... } ]
(using parentheses if you want) looks good enough for me, and something like
the Array#cassoc I showed before would do fine in this case.
···
On Mon, Aug 14, 2006 at 12:27:07AM +0900, James Edward Gray II wrote: