On 2010/12/12 20:13, Tanaka Akira wrote:
> Hi.
>
> How about a method for converting enumerable to hash?

There are already such methods. At least group_by. Your proposal seems 
to be a very special way to convert an enumerable to a hash.

>    enum.categorize([opts]) {|elt| [key1, ..., val] } ->  hash
>
> categorizes the elements in _enum_ and returns a hash.
>
> The block is called for each elements in _enum_.
> The block should return an array which contains
> one or more keys and one value.
>
>    p (0..10).categorize {|e| [e % 3, e % 5] }
>    #=>  {0=>[0, 3, 1, 4], 1=>[1, 4, 2, 0], 2=>[2, 0, 3]}

I'm trying to understand your example. Let me make a table.

original value     return_value[0]    return_value[1]
0                  0                  0
1                  1                  1
2                  2                  2
3                  0                  3
4                  1                  4
5                  2                  0
6                  0                  1
7                  1                  2
8                  2                  3
9                  0                  4
10                 1                  0

I think I get the idea of how this is supposed to work. But I'm not sure 
what the actual use cases would be. Can you give some?

For this variant, a Ruby equivalent is:

h = {}
(0..10).each do |e|
   h[e%3] ||= []
   h[e%3] << e%5
end
p h

Or shorter:

h = {}
(0..10).each { |e| (h[e%3] ||= []) << e%5 }
p h

I admit that it is more elegant if the initialization and the final line 
can be avoided, but I think that's an issue that can be dealt with 
separately.

> The keys and value are used to construct the result hash.
> If two or more keys are provided
> (i.e. the length of the array is longer than 2),
> the result hash will be nested.
>
>    p (0..10).categorize {|e| [e&4, e&2, e&1, e] }
>    #=>  {0=>{0=>{0=>[0, 8],
>    #            1=>[1, 9]},
>    #        2=>{0=>[2, 10],
>    #            1=>[3]}},
>    #    4=>{0=>{0=>[4],
>    #            1=>[5]},
>    #        2=>{0=>[6],
>    #            1=>[7]}}}
>
> The value of innermost hash is an array which contains values for
> corresponding keys.
> This behavior can be customized by :seed, :op and :update option.
>
> This method can take an option hash.
> Available options are follows:

Who will be able to remember exactly what these options are,...? Most 
other methods, in particular on Enumerables, don't have that many 
options. I think that's for a good reason.

Regards,   Martin.


> - :seed specifies seed value.
> - :op specifies a procedure from seed and value to next seed.
> - :update specifies a procedure from seed and block value to next seed.
>
> :seed, :op and :update customizes how to generate
> the innermost hash value.
> :seed and :op behavies like Enumerable#inject.
>
> If _seed_ and _op_ is specified, the result value is generated as follows.
>    op.call(..., op.call(op.call(seed, v0), v1), ...)
>
> :update works as :op except the second argument is the block value itself
> instead of the last value of the block value.
>
> If :seed option is not given, the first value is used as the seed.
>
>    # The arguments for :op option procedure are the seed and the value.
>    # (i.e. the last element of the array returned from the block.)
>    r = [0].categorize(:seed =>  :s,
>                       :op =>  lambda {|x,y|
>                         p [x,y]               #=>  [:s, :v]
>                         1
>                       }) {|e|
>      p e #=>  0
>      [:k, :v]
>    }
>    p r #=>  {:k=>1}
>
>    # The arguments for :update option procedure are the seed and the array
>    # returned from the block.
>    r = [0].categorize(:seed =>  :s,
>                       :update =>  lambda {|x,y|
>                         p [x,y]               #=>  [:s, [:k, :v]]
>                         1
>                       }) {|e|
>      p e #=>  0
>      [:k, :v]
>    }
>    p r #=>  {:k=>1}
>
> The default behavior, array construction, can be implemented as follows.
>    :seed =>  nil
>    :op =>  lambda {|s, v| !s ? [v] : (s<<  v) }
>
> Note that matz doesn't find satisfact in the method name, "categorize".
> [ruby-dev:42681]
>
> Also note that matz wants another method than this method,
> which the hash value is the last value, not an array of all values.
> This can be implemented by enum.categorize(:op=>lambda {|x,y| y}) { ... }.
> But good method name is not found yet.
> [ruby-dev:42643]

-- 
#-# Martin J. Dst, Professor, Aoyama Gakuin University
#-# http://www.sw.it.aoyama.ac.jp   mailto:duerst / it.aoyama.ac.jp