Dynamic nested each in ruby 1.8.7?

T

Toi Toi

How can one have a function that uses a dynamic amount of each
statements? Below is the code for level 3. Is there a way to define this
easily using recursion? I want to avoid having a separate function for
each level.

def calc nums, level
tmp = []
nums.each{ |n| tmp.push n
nums.each{ |n2| tmp.push n+n2
nums.each{ |n3| tmp.push n+n2+n3
}}}
tmp
end

puts calc(["0", "1"], 3)
 
F

Florian Gilcher

Wow,

what are you trying to accomplish? Permutations maybe?

I can think of some solutions for dynamical nested each-statments, but
I frankly can't think of a problem that I would solve using them.

Regards,
Florian Gilcher

How can one have a function that uses a dynamic amount of each
statements? Below is the code for level 3. Is there a way to define
this
easily using recursion? I want to avoid having a separate function for
each level.

def calc nums, level
tmp = []
nums.each{ |n| tmp.push n
nums.each{ |n2| tmp.push n+n2
nums.each{ |n3| tmp.push n+n2+n3
}}}
tmp
end

puts calc(["0", "1"], 3)

--
Florian Gilcher

smtp: (e-mail address removed)
jabber: (e-mail address removed)
gpg: 533148E2
 
H

Harry Kakueki

How can one have a function that uses a dynamic amount of each
statements? Below is the code for level 3. Is there a way to define this
easily using recursion? I want to avoid having a separate function for
each level.

def calc nums, level
tmp = []
nums.each{ |n| tmp.push n
nums.each{ |n2| tmp.push n+n2
nums.each{ |n3| tmp.push n+n2+n3
}}}
tmp
end

puts calc(["0", "1"], 3)
--

Does this give you the right output?
No recursion, but...

def calc(n, v)
h,t = Hash[*(0...n.size).zip(n).flatten],[]
(1..v).each{|x| (0...n.size**x).each{|y| t << y.to_s(n.size).rjust(x,"0")}}
t.map{|a| a.split(//).map{|b| h[b.to_i]}.join}.sort
end

p calc(["0","1"], 3)


Harry
 
T

Toi Toi

That function does not give the correct output for larger arrays. The
level functions can be generated with eval, see the code below. However
there must be a better Ruby way.

def calc level
tmp = ["def calcd nums\ntmp=[]\n"]
str = "n1"
num = 1

level.times {
tmp.push "nums.each{ |n#{num}| tmp.push #{str}\n"
str = str+" + n#{num+=1}"
}
level.times { tmp.push "}"}

tmp.push "\ntmp\n"
tmp.push "end"
tmp.to_s
end
array, times = ('1'..'10').to_a, 3
eval(calc(times))
p calcd(array)


Harry said:
}}}
tmp
end

puts calc(["0", "1"], 3)
--

Does this give you the right output?
No recursion, but...

def calc(n, v)
h,t = Hash[*(0...n.size).zip(n).flatten],[]
(1..v).each{|x| (0...n.size**x).each{|y| t <<
y.to_s(n.size).rjust(x,"0")}}
t.map{|a| a.split(//).map{|b| h[b.to_i]}.join}.sort
end

p calc(["0","1"], 3)


Harry
 
H

Harry Kakueki

That function does not give the correct output for larger arrays. The
level functions can be generated with eval, see the code below. However
there must be a better Ruby way.

def calc level
tmp = ["def calcd nums\ntmp=[]\n"]
str = "n1"
num = 1

level.times {
tmp.push "nums.each{ |n#{num}| tmp.push #{str}\n"
str = str+" + n#{num+=1}"
}
level.times { tmp.push "}"}

tmp.push "\ntmp\n"
tmp.push "end"
tmp.to_s
end
array, times = ('1'..'10').to_a, 3
eval(calc(times))
p calcd(array)



def calc_new(arr,l)
h,t = Hash[*(0...arr.size).zip(arr).flatten],[]
(1..l).each do |z|
(0...arr.size**l).each do |x|
t << x.to_s(arr.size).rjust(z,"0")
end
end
t.uniq.sort.map{|c| c.split(//).map{|d| h[d.to_i]}.join}
end

p calc_new((1..10).to_a, 3)


Harry
 
H

Harry Kakueki

def calc_new(arr,l)
h,t = Hash[*(0...arr.size).zip(arr).flatten],[]
(1..l).each do |z|
(0...arr.size**l).each do |x|
t << x.to_s(arr.size).rjust(z,"0")
end
end
t.uniq.sort.map{|c| c.split(//).map{|d| h[d.to_i]}.join}
end

p calc_new((1..10).to_a, 3)

Not always correct.
Hmmmmm.....
 
H

Harry Kakueki

How can one have a function that uses a dynamic amount of each
statements? Below is the code for level 3. Is there a way to define this
easily using recursion? I want to avoid having a separate function for
each level.

def calc nums, level
tmp = []
nums.each{ |n| tmp.push n
nums.each{ |n2| tmp.push n+n2
nums.each{ |n3| tmp.push n+n2+n3
}}}
tmp
end

puts calc(["0", "1"], 3)
--

I think this will do it if your array size <= 36

def calc_new(arr,l)
h,t = Hash[*(0...arr.size).zip(arr).flatten],[]
p h
(1..l).each do |z|
(0...arr.size**l).each do |x|
t << x.to_s(arr.size).rjust(z,"0")
end
end
t.uniq.sort.map{|c| c.split(//).map{|d| h[d.to_i(arr.size)]}.join}
end

p calc_new((1..12).to_a, 3)


Harry
 
T

Toi Toi

I think this will do it if your array size <= 36

That code does work well for array.size <= 36, however I need a dynamic
amount without an arbitrary limitation.

The data set causes an illegal radix ArgumentError since it is indeed >
36. Using eval any array size can be handled. I may just use Java if a
robust solution is not possible in Ruby without resorting to eval.
 
S

Suraj Kurapati

Toi said:
def calc nums, level
tmp = []
nums.each{ |n| tmp.push n
nums.each{ |n2| tmp.push n+n2
nums.each{ |n3| tmp.push n+n2+n3
}}}
tmp
end

puts calc(["0", "1"], 3)

Look at Array#enumeration in my ISC-licensed combinatorics library:
http://github.com/sunaku/inochi/blob/master/lib/inochi/util/combo.rb

With that library, your question can be answered as follows:

sun@yantram ~/s/inochi> irb -r pp -r lib/inochi/util/combo.rb
## ruby 1.9.1p243 (2009-07-16 revision 24175) [i686-linux]
pp ["0", "1"].enumeration(3)
[["0", "0", "0"],
["0", "0", "1"],
["0", "1", "0"],
["0", "1", "1"],
["1", "0", "0"],
["1", "0", "1"],
["1", "1", "0"],
["1", "1", "1"]]
=> nil
 
S

Suraj Kurapati

Florian said:
what are you trying to accomplish? Permutations maybe?
I frankly can't think of a problem that I would solve using them.

One application is exhaustive, brute-force unit testing. For example,
in my eRuby processor, it was necessary to test proper handling of
eRuby directives surrounded by various amounts and kinds of whitespace
(empty string, spaces, tabs, and line breaks):

http://github.com/sunaku/ember/blob/master/test/ember/template.rb
 
A

Aldric Giacomoni

S

Suraj Kurapati

Aldric said:
My jaw is gaping at the code I read..

:) To be fair, my library also implements combinations and
enumerations: both in the "n choose k" subset form and in the exhaustive
"all items in this list" form.

It's interesting to note that the only algorithmic difference between
permutations and combinations is that combinations prevent already
visited vertices from being visited again in subsequent iterations,
whereas permutations do not. I was quite pleased with this observation,
because it allowed me to base nPk and nCk on a single implementation:
pnk_cnk_impl().

I did not understand how to use that simpler permutations() method:

skurapati@skurapati-dt ~> irb
## ruby 1.8.7 (2008-08-11 patchlevel 72) [i486-linux]?> li.each do |element|
?> permutations(li.select() {|n| n != element}) \
?> {|val| yield([element].concat val)}
end
end
end => nil
permutations ["0", "1"]
LocalJumpError: no block given
from (irb):7:in `permutations'
from (irb):3:in `permutations'
from (irb):6:in `permutations'
from (irb):5:in `each'
from (irb):5:in `permutations'
from (irb):12
permutations ["0", "1"] do end => ["0", "1"]
permutations ["0", "1"] do |val| val end => ["0", "1"]
permutations ["0", "1", "2"] do end => ["0", "1", "2"]
permutations ["0", "1", "2"] do |val| val end => ["0", "1", "2"]
permutations ["0", "1", "2"] do |val| [val] end
=> ["0", "1", "2"]

Any suggestions?
 
S

Suraj Kurapati

Suraj said:
I did not understand how to use that simpler permutations() method:
Any suggestions?

Never mind, I figured it out:
result = [] => []
permutations ["0", "1", "2"] do |val| result << val end => ["0", "1", "2"]
pp result
[["0", "1", "2"],
["0", "2", "1"],
["1", "0", "2"],
["1", "2", "0"],
["2", "0", "1"],
["2", "1", "0"]]
=> nil

Pretty cool. An improvement would be to return an Enumerator.
 
G

Gary Wright

Pretty cool. An improvement would be to return an Enumerator.

How about:


module Enumerable
def permutations
return enum_for:)permutations) unless block_given?

if length < 2
yield self
else
each do |element|
select { |candidate|
candidate != element
}.permutations { |smaller|
yield [element, *smaller]
}
end
end
end
end


[1,2,3].permutations { |x| p x }

p [1,2,3].permutations.map { |x| x.reverse }


Gary Wright
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,166
Messages
2,570,901
Members
47,442
Latest member
KevinLocki

Latest Threads

Top