# \[Puzzle\] How to do parameter variation?

**URL:** <https://www.ruby-forum.com/t/puzzle-how-to-do-parameter-variation/78612>\
**Category:** Ruby\
**Created:** [December 7, 2006, 8:25am UTC](https://www.ruby-forum.com/t/puzzle-how-to-do-parameter-variation/78612 "2006-12-07T08:25:41Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![gfburke](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/ea5d25/32.png) [@gfburke](https://www.ruby-forum.com/u/gfburke)\
**Post date:** [December 7, 2006, 8:25am UTC](https://www.ruby-forum.com/t/puzzle-how-to-do-parameter-variation/78612/1 "2006-12-07T08:25:41Z")

</div>

Suppose you want to do several runs of a program or function, varying  
the parameters each time. You start with a hash of parameter lists:

```
params = { speed=>[1,2,3], beta=>[0.1, 0.002, 0.4], x=>['a', 'b'] }

```

Given this set, you’ll call the test function 18 times:

test\_function( {speed=\>1, beta=\>0.1, x=\>‘a’} )  
test\_function( {speed=\>1, beta=\>0.1, x=\>‘b’} )  
test\_function( {speed=\>1, beta=\>0.002, x=\>‘a’} )  
… etc

So the puzzle is how to take the original params list and generate a  
list of all the combinations of the parameters? The resulting parameter  
sets will be passed one at a time to the function as shown above.

Notes:

- I used hashes and lists to explain the problem. Maybe there’s a better  
way.
- You don’t know how many parameters will be given.
- The number of values for each parameter is unknown in advance.
- The parameters have different types, as shown above. Each parameter’s  
values are all the same type, though.

---

<div class="post-metadata">

**Author:** ![gfburke](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/ea5d25/32.png) [@gfburke](https://www.ruby-forum.com/u/gfburke)\
**Post date:** [December 7, 2006, 2:46pm UTC](https://www.ruby-forum.com/t/puzzle-how-to-do-parameter-variation/78612/2 "2006-12-07T14:46:52Z")

</div>

On Thu, Dec 07, 2006 at 04:25:43PM +0900, Gary B. wrote:  
}  
} Suppose you want to do several runs of a program or function, varying  
} the parameters each time. You start with a hash of parameter lists:  
}  
} params = { speed=\>[1,2,3], beta=\>[0.1, 0.002, 0.4], x=\>[‘a’, ‘b’]  
}  
}  
} Given this set, you’ll call the test function 18 times:  
}  
} test\_function( {speed=\>1, beta=\>0.1, x=\>‘a’} )  
} test\_function( {speed=\>1, beta=\>0.1, x=\>‘b’} )  
} test\_function( {speed=\>1, beta=\>0.002, x=\>‘a’} )  
} … etc  
}  
} So the puzzle is how to take the original params list and generate a  
} list of all the combinations of the parameters? The resulting  
parameter  
} sets will be passed one at a time to the function as shown above.  
}  
} Notes:  
} - I used hashes and lists to explain the problem. Maybe there’s a  
better  
} way.  
} - You don’t know how many parameters will be given.  
} - The number of values for each parameter is unknown in advance.  
} - The parameters have different types, as shown above. Each  
parameter’s  
} values are all the same type, though.

params = { :speed =\> [1,2,3], :beta =\> [0.1, 0.002, 0.4], :x =\> [‘a’,  
‘b’] }

all = params.inject([{}]) do |perms,(k,list)|  
perms.inject([]) do |expanded,base|  
list.each do |v|  
expanded \<\< base.merge(k =\> v)  
end  
expanded  
end  
end

require ‘yaml’  
puts all.size  
puts all.to\_yaml

–Greg

---

<div class="post-metadata">

**Author:** ![gfburke](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/ea5d25/32.png) [@gfburke](https://www.ruby-forum.com/u/gfburke)\
**Post date:** [December 7, 2006, 3:22pm UTC](https://www.ruby-forum.com/t/puzzle-how-to-do-parameter-variation/78612/3 "2006-12-07T15:22:57Z")

</div>

On Dec 7, 2006, at 1:25 AM, Gary B. wrote:

> test\_function( {speed=\>1, beta=\>0.1, x=\>‘b’} )  
> test\_function( {speed=\>1, beta=\>0.002, x=\>‘a’} )  
> … etc

See if this gives you some ideas:

#!/usr/bin/env ruby -w

def call\_with(meth, params, selected = Hash.new)  
params = params.dup  
key = params.keys.sort\_by { |k| k.to\_s }.first  
choices = params.delete(key)

choices.each do |choice|  
selected = selected.merge(key =\> choice)  
if params.empty?  
send(meth, selected)  
else  
call\_with(meth, params, selected)  
end  
end  
end

def print\_args(args)  
p args  
end

call\_with :print\_args, :speed =\> [1, 2, 3],  
:beta =\> [0.1, 0.002, 0.4],  
:x =\> [“a”, “b”]

# \>\> {:speed=\>1, :beta=\>0.1, :x=\>“a”}

# \>\> {:speed=\>1, :beta=\>0.1, :x=\>“b”}

# \>\> {:speed=\>2, :beta=\>0.1, :x=\>“a”}

# \>\> {:speed=\>2, :beta=\>0.1, :x=\>“b”}

# \>\> {:speed=\>3, :beta=\>0.1, :x=\>“a”}

# \>\> {:speed=\>3, :beta=\>0.1, :x=\>“b”}

# \>\> {:speed=\>1, :beta=\>0.002, :x=\>“a”}

# \>\> {:speed=\>1, :beta=\>0.002, :x=\>“b”}

# \>\> {:speed=\>2, :beta=\>0.002, :x=\>“a”}

# \>\> {:speed=\>2, :beta=\>0.002, :x=\>“b”}

# \>\> {:speed=\>3, :beta=\>0.002, :x=\>“a”}

# \>\> {:speed=\>3, :beta=\>0.002, :x=\>“b”}

# \>\> {:speed=\>1, :beta=\>0.4, :x=\>“a”}

# \>\> {:speed=\>1, :beta=\>0.4, :x=\>“b”}

# \>\> {:speed=\>2, :beta=\>0.4, :x=\>“a”}

# \>\> {:speed=\>2, :beta=\>0.4, :x=\>“b”}

# \>\> {:speed=\>3, :beta=\>0.4, :x=\>“a”}

# \>\> {:speed=\>3, :beta=\>0.4, :x=\>“b”}

James Edward G. II

---

<div class="post-metadata">

**Author:** ![gfburke](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/ea5d25/32.png) [@gfburke](https://www.ruby-forum.com/u/gfburke)\
**Post date:** [December 8, 2006, 4:28am UTC](https://www.ruby-forum.com/t/puzzle-how-to-do-parameter-variation/78612/4 "2006-12-08T04:28:37Z")

</div>

Cool. While I study the others, here’s my solution. Looks like it’s  
similar to Greg’s.

–Gary

# expand\_hash\_lists

# 

# note that accumulating lists must be passed in as the first argument

# 

def expand\_hash\_lists(a1, a2)  
a1.inject([]){|acc,f| a2.inject(acc){|a,b| a \<\< [b]+  
(f.is\_a?(Hash)?[f]:f)}}  
end

if **FILE** == $0

# tests of expand\_hash\_lists

ah=[{‘a’=\>1}, {‘a’=\>2}, {‘a’=\>3}]  
bh=[{‘b’=\>21}, {‘b’=\>22}, {‘b’=\>23}]  
ch=[{‘c’=\>31}, {‘c’=\>32}, {‘c’=\>33}]  
dh=[{‘d’=\>41}, {‘d’=\>42}, {‘d’=\>43}]

abh = expand\_hash\_lists(ah, bh)  
abch = expand\_hash\_lists(abh, ch)  
p expand\_hash\_lists(abch, dh).inspect

# Additional tests

p “----”  
p [[{‘a’=\>1}], [{‘b’=\>2}]].inject{|acc, vl| expand\_hash\_lists(acc,  
vl)}.inspect  
p “----”  
p [[{‘a’=\>1}, {‘a’=\>3}], [{‘b’=\>2}]].inject{|acc, vl|  
expand\_hash\_lists(acc, vl)}.inspect  
p “----”  
p [[{‘a’=\>1}, {‘a’=\>3}], [{‘b’=\>2}, {‘b’=\>4}]].inject{|acc, vl|  
expand\_hash\_lists(acc, vl)}.inspect  
end
