From: Robert Klemme Date: 2005-07-08T23:25:47+09:00 Subject: Re: accessing index inside map David A. Black wrote: > Hi -- > > On Fri, 8 Jul 2005, Robert Klemme wrote: > >> Michael Campbell wrote: >>> On 7/8/05, David A. Black 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 => # >> 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 => #: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