Can it be shorter?


#1

doing access control on rails controller,

------ I have this input --------------
hash = {“index” => “list”,
[“edit”, “update”] => “manage_one”,
[“new”, “create”, “destroy”] => “manage_all”}

------- I want this output ----------
{“index”=>“list”,
“edit”=>“manage_one”,
“update”=>“manage_one”,
“new”=>“manage_all”,
“create”=>“manage_all”,
“destroy”=>“manage_all”
}

------ I have this code ------------
hash = Hash[*hash.to_a.collect{|x|
Array === x[0] ? x[0].zip([x[1]]*x[0].size) : x
}.flatten]

----- I want shorter code ------

thanks.


#2

a little clearer than previous one.

hash = Hash[hash.inject([]){|arr, (k, v)|
arr += Array === k ? k.zip([v]
k.size)
: [k, v]
}.flatten]


#3

Dorren wrote:

“update”=>“manage_one”,
----- I want shorter code ------
What about this:

h = {}
for k,v in hash
[k].flatten.each {|l| h[l] = v}
end
hash = h

=> {“new”=>“manage_all”, “edit”=>“manage_one”,
“destroy”=>“manage_all”, “create”=>“manage_all”, “index”=>“list”,
“update”=>“manage_one”}

Cheers,

Vincent


#4

Vincent F. wrote:

h = {}
for k,v in hash
[k].flatten.each {|l| h[l] = v}
end
hash = h

Actually, I’ve got shorter ;-):

h = {}
for k,v in hash
[*k].each {|l| h[l] = v}
end
hash = h

Vince


#5

better, thank tou.

On Jan 24, 6:14 pm, Vincent F. removed_email_address@domain.invalid


#6

On Jan 24, 5:01 pm, “Dorren” removed_email_address@domain.invalid wrote:

a little clearer than previous one.

hash = Hash[hash.inject([]){|arr, (k, v)|
arr += Array === k ? k.zip([v]
k.size)
: [k, v]
}.flatten]

Hash[ *hash.map{|k,v| k=[*k]; k.zip([v]*k.size) }.flatten ]


#7

Vincent F. removed_email_address@domain.invalid writes:

Actually, I’ve got shorter ;-):

h = {}
for k,v in hash
[*k].each {|l| h[l] = v}
end
hash = h

Well, if we’re golfing:

h={};hash.map{|k,v|[*k].map{|t|h[t]=v}};h


#8

On 25.01.2007 03:29, Daniel M. wrote:

Well, if we’re golfing:

h={};hash.map{|k,v|[*k].map{|t|h[t]=v}};h

Not really shorter but I though there should be at least one solution
with #inject:

hash.inject({}){|h,(k,v)| k.to_a.each {|x| h[x]=v};h}
=> {“new”=>“manage_all”, “edit”=>“manage_one”, “destroy”=>“manage_all”,
“create”=>“manage_all”, “index”=>“list”, “update”=>“manage_one”}

hash.inject({}){|h,(k,v)| k.each {|x| h[x]=v} rescue h[k]=v;h}
=> {“new”=>“manage_all”, “edit”=>“manage_one”, “destroy”=>“manage_all”,
“create”=>“manage_all”, “index”=>“list”, “update”=>“manage_one”}

:slight_smile:

robert


#9

On Jan 24, 2007, at 15:20, Vincent F. wrote:

for k,v in hash
[*k].each {|l| h[l] = v}
end
hash = h

but fastest (I assume all entries worked correctly):

$ ruby bm.rb
Rehearsal --------------------------------------------------------
original 10.440000 0.010000 10.450000 ( 10.492738)
original clean 11.480000 0.040000 11.520000 ( 11.632237)
vince 5.210000 0.010000 5.220000 ( 5.264394)
william 12.760000 0.020000 12.780000 ( 12.814230)
daniel 6.900000 0.010000 6.910000 ( 6.924297)
robert inject 6.560000 0.000000 6.560000 ( 6.588160)
robert inject rescue 6.080000 0.010000 6.090000 ( 6.094140)
---------------------------------------------- total: 59.530000sec

                        user     system      total        real

original 10.450000 0.010000 10.460000 ( 10.467971)
original clean 11.490000 0.030000 11.520000 ( 11.600672)
vince 5.210000 0.000000 5.210000 ( 5.219863)
william 12.820000 0.010000 12.830000 ( 12.839722)
daniel 6.930000 0.010000 6.940000 ( 6.945329)
robert inject 6.580000 0.010000 6.590000 ( 6.591095)
robert inject rescue 6.080000 0.000000 6.080000 ( 6.117226)


#10

There’s a glitch, which is not yet mentioned…

Consider this old hash: {[“A”, “B”]=>“C”, [“B”, “A”]=>“D”}

What’s the value of new_hash[“A”]? Is it “C”, or is it “D”?

That depends on the order on which you build the new hash.
Which depends on the order in which you walk through the old
hash. Which isn’t deterministic, AFAIK. Maybe it is
determinstic if you know in which order the old hash was built.
But, given a hash, you simply don’t know the order in which
you walk through it, so you don’t know the order in which the
new hash will be built, so you don’t know what the result is
going to be. Cool…

Adding a sort to the algorithm fixes this.

gegroet,
Erik V. - http://www.erikveen.dds.nl/


hash.collect do |k,v|
[[k].flatten, v]
end.sort.inject({}) do |h,(ks,v)|
ks.each do |k|
h[k] = v
end
h
end