Enumerable#unassociate

Have a look:

module Enumerable

# Take an associative array and unassociate it.
#
#   [[:a,1], [:b,2]].unassociate.to_a     #=> [:a, [1], :b, [2]]
#   [[:a,1], [:b,2]].unassociate(1).to_a  #=> [:a, 1, :b, 2]
#
def unassociate(index = 1..-1)
  return to_enum(:unassociate, index) unless block_given?

  each do |v|
    case v
    when Array
      yield v[0]
      yield v[index]
    else
      yield v
      yield nil
    end
  end
end

end

Is it a good method name? Is 1…-1 the best default?

Other thoughts/ suggestions?

On Monday, June 25, 2012 2:38:48 AM UTC-4, Robert K. wrote:

What’s the use case for this?

In my case it’s supplemental to another method I am working on. I have
no
name for it yet, so call it #h.

Convert an Enumerable object to a Hash.

[:a, 1, :b, 2].h

#=> {:a=>1, :b=>2}

[:a, 1, :b, 2, :a, 3].h{ |v0,v1| v0.to_i + v1 }

#=> {:a=>4, :b=>2}

def h(init={})
h = init

if block_given?
  each_slice(2) do |k,v|
    h[k] = yield h[k], v
  end
else
  each_slice(2){ |k,v| h[k] = v }
end

h

end

The #unassociate method qould be of use as a preparation for using h,
since
this doesn’t work with associative arrays (like whats returned by
Hash#to_a).

[[:a,1], [:b,2], [:a,3]].unassociate.h{ |v0, v1| v0 << v1 }
#=> {:a=>[1,3], :b=>2}

On Mon, Jun 25, 2012 at 1:35 AM, Intransition [email protected]
wrote:

Have a look:

module Enumerable

Take an associative array and unassociate it.

[[:a,1], [:b,2]].unassociate.to_a #=> [:a, [1], :b, [2]]

[[:a,1], [:b,2]].unassociate(1).to_a #=> [:a, 1, :b, 2]

def unassociate(index = 1…-1)

Other thoughts/ suggestions?

What’s the use case for this?

Kind regards

robert

On Monday, June 25, 2012 12:00:01 PM UTC-4, Robert K. wrote:

And what’s the use case for that method?

To convert an Enumerable to a Hash. Sorry, I should have specified
that.

def h(init={})
h = init

You never assign h nor init so you could completely get rid of h.

??? What about h[k] = v, or am I misunderstanding?

if block_given?
  each_slice(2) do |k,v|
    h[k] = yield h[k], v

I find it strange that you yield h[k] and not k. The caller can never
know what k was, while if you pass k he can look up in init and obtain
the value you now yield.

The idea behind that is to allow Symbol#to_proc to be useful.

a = [:a, 1, :b, 2, :a, 3]

i = Hash.new{ |h,k| h[k] = [] }
a.h(i, &:+) #=> {:a=>[1,3], :b=>[2]}

I considered other interfaces to the block but this one seemed like it
would be the most useful b/c of this.

It’s totally mysterious what you are after here. The fact that you do

not have a name yet might be indicative that this methods are probably
not such a good idea. They do not look generally useful to me.

No, that’s me simply not giving enough initial context, which sometimes
I
do so not to skew others consideration. But not very helpful in the
case,
clearly.

On Mon, Jun 25, 2012 at 4:59 PM, Intransition [email protected]
wrote:

On Monday, June 25, 2012 2:38:48 AM UTC-4, Robert K. wrote:

What’s the use case for this?

In my case it’s supplemental to another method I am working on.

And what’s the use case for that method?

def h(init={})
h = init

You never assign h nor init so you could completely get rid of h.
Btw, if you call the argument Hash “init” I would not necessarily
expect it to be modified. Maybe it’s better to do

h = init.dup

Or, to save one instantiation

def h(init = nil)
h = init ? init.dup : {}

if block_given?
each_slice(2) do |k,v|
h[k] = yield h[k], v

I find it strange that you yield h[k] and not k. The caller can never
know what k was, while if you pass k he can look up in init and obtain
the value you now yield.

end
else
each_slice(2){ |k,v| h[k] = v }
end

h
end

It’s totally mysterious what you are after here. The fact that you do
not have a name yet might be indicative that this methods are probably
not such a good idea. They do not look generally useful to me.

Kind regards

robert

On Mon, Jun 25, 2012 at 9:57 PM, Intransition [email protected]
wrote:

On Monday, June 25, 2012 12:00:01 PM UTC-4, Robert K. wrote:

And what’s the use case for that method?

To convert an Enumerable to a Hash. Sorry, I should have specified that.

But not only that: you need a Hash as input to do transformations
along the way. Wouldn’t this be more reasonable if you just want to
convert to a Hash?

def to_hash
{}.tap do |h|
each_slice 2 do |k, v|
k, v = yield k, v if block_given?
h[k] = v
end
end
end

def h(init={})
h = init

You never assign h nor init so you could completely get rid of h.

??? What about h[k] = v, or am I misunderstanding?

Yes. There is just one assignment to h.

I find it strange that you yield h[k] and not k. The caller can never
know what k was, while if you pass k he can look up in init and obtain
the value you now yield.

The idea behind that is to allow Symbol#to_proc to be useful.

a = [:a, 1, :b, 2, :a, 3]

i = Hash.new{ |h,k| h[k] = [] }
a.h(i, &:+) #=> {:a=>[1,3], :b=>[2]}

irb(main):029:0> i = Hash.new{ |h,k| h[k] = [] }
=> {}
irb(main):030:0> a.each_slice(2){|k,v| i[k] << v}
=> nil
irb(main):031:0> i
=> {:a=>[1, 3], :b=>[2]}

clearly.
I agree with Bartosz, there is a lot of magic in there and the method
does more than one thing which is always suspicious. If you want to
do a transformation a la #map along the way I would leave that
completely to a block passed and not restrict it to a Hash (well, a
Proc might work as well - but still).

Kind regards

robert

I still don’t see why that would be better. Both of your methods are
way too magical to be understandable.

This, while longer, at least makes sense.

a = [:a, 1, :b, 2, :a, 3]
Hash[ a.each_slice(2).group_by{|s,n| s}.map{|k,v| [k, v.map{|s,n| n}]
} ] #=> {:a=>[1,3], :b=>[2]}

– Matma R.