Robert Klemme
7/8/2005 2:17:00 PM
David A. Black wrote:
> Hi --
>
> On Fri, 8 Jul 2005, Robert Klemme wrote:
>
>> Michael Campbell wrote:
>>> On 7/8/05, David A. Black <dblack@wobblini.net> wrote:
>>>> Hi --
>>>
>>>> I'd still like to see #man_with_index added to Enumerable.
>>>
>>> "index" implies an ordering, which maps by definition don't have.
>>> Shouldn't that be something along the lines of "#map_with_key"?
>>>
>>> But point taken; it seems a natural thing, regardless of actual
>>> name, to be in Enumerable.
>>
>> Key is ambiguous with Hashes... Apart from that: I'm not really sure
>> whether I like that idea. The basic property of an Enumerable is
>> that it can be enumerated with each. There are no guarantees about
>> order etc. each_with_index is really only there to simplify
>> counting. If you want map_with_index then you'd probably have to
>> provide inject_with_index, find_with_index etc. Personally I think
>> that map_with_index is rarely used to justify adding this to the std
>> lib. Just my 0.02 EUR of course.
>
> I'm not a stickler for symmetry (my slogan for Ruby is "The triumph of
> balance over symmetry" :-) but it does seem a little arbitrary to have
> it recognized that #each_with_index is important for arrays, and #map
> is important, but #map_with_index isn't. (I emphasize "arrays"; I've
> never seen a case where it was needed or useful for hashes.) I don't
> think there's any implication that you'd have to have *_with_index.
> Nor any demand: I've never seen anyone implement #find_with_index
> (what exactly would it do? :-) but I've seen many of
> Array#each_with_index.
What about removing this completely from Enumerable and doing it like
this:
class Indexer
include Enumerable
def initialize(obj)
# @meth = meth
@obj = obj
end
def each
i = 0
@obj.each {|*a| yield *(a << i); i+=1}
self
end
end
module Enumerable
def indexer() Indexer.new(self) end
end
>> aa=[10,20,30]
=> [10, 20, 30]
>> aa.indexer.each {|a,i| printf "%4d. %s\n", i, a}
0. 10
1. 20
2. 30
=> #<Indexer:0x1017edc8 @obj=[10, 20, 30]>
>> aa.indexer.map {|a,i| a*i}
=> [0, 20, 60]
>> aa.indexer.inject([]) {|ar,(a,i)| ar << sprintf( "%4d. %s", i, a)}
=> [" 0. 10", " 1. 20", " 2. 30"]
>> hh={10=>:a, 20=>:b, 30=>:c}
=> {30=>:c, 20=>:b, 10=>:a}
>> hh.indexer.each {|(k,v),i| printf "%4d. %s => %s\n", i, k, v}
0. 30 => c
1. 20 => b
2. 10 => a
=> #<Indexer:0x101a1940 @obj={30=>:c, 20=>:b, 10=>:a}>
>> hh.indexer.map {|(k,v),i| "#{k}=>#{v}" * i}
=> ["", "20=>b", "10=>a10=>a"]
>> hh.indexer.inject([]) {|ar,((k,v),i)| ar << sprintf( "%4d. %s => %s",
i, k, v)}
=> [" 0. 30 => c", " 1. 20 => b", " 2. 10 => a"]
Admittedly the last example looks a bit awkward - but #inject is not easy
anyway and it stays consistend with the others.
Kind regards
robert