ruby - Permutation between different elements in an array
ar = [["a, b, c"], ["lol1, lol2, lol3"], ["so1, so2, so3"]]
p maybe_this = ar.map{|sub_ar| sub_ar.first.split(', ')}
#[["a", "b", "c"], ["lol1", "lol2", "lol3"], ["so1", "so2", "so3"]]
idx = [2,1,3]
#indexing of an array is zero-based
p idx.map!{|i| i-1} #[1,0,2]
p res = maybe_this.map{|sub_ar| sub_ar.values_at(*idx)}
#[["b", "a", "c"], ["lol2", "lol1", "lol3"], ["so2", "so1", "so3"]]
The short story: the values_at method takes multiple arguments; *idx
splats an array into multiple arguments.
Permutations in Ruby - unsure how to handle
First, check size of that permutation
a.permutation(10).size
=> 670442572800
It's huge. What you can do instead is to use Array#repeated_permutations
on smaller array. Check it here:
b = [1, 2] # Only unique elements
b.repeated_permutation(10) # Returns enumerable
b.repeated_permutation(10).to_a # Creates array with all of permutations
Those permutations are already unique (which u can check by printing it size with and without Array#uniq
)
Finding all permutations of numbers plucked from an array which sum to 16
For all permutations, including duplicates, one might use Array#repeated_permutation
:
d = [2,3,4,5,6,7,8]
number_of_divisions = [3,4,5]
number_of_divisions.flat_map do |n|
d.repeated_permutation(n).reject do |p| # no need `to_a`
p.inject(:+) != 16
end
end
or, even better with Array#repeated_combination
:
number_of_divisions.flat_map do |n|
d.repeated_combination(n).reject do |p| # no need `to_a`
p.inject(:+) != 16
end
end
Generate combinations of values from multiple arrays
If you want all the possible combinations, there's no alternative other than iterating through each of the elements for all arrays.
Creating hashes is not difficult either.
Try this.
a = [1, 2, 3, 4, 5]
b = ['A', 'B', 'C', 'D', 'E']
c = ['J', 'K', 'L', 'M', 'N']
d = ['v', 'w', 'x', 'y', 'z']
result = []
a.each do |a_elem|
b.each do |b_elem|
c.each do |c_elem|
d.each do |d_elem|
result << {a: a_elem, b: b_elem, c: c_elem, d: d_elem}
end
end
end
end
puts "#{result}"
I believe this is what you are looking for.
Combination of two arrays in Ruby
You can use product
to get the cartesian product of the arrays first, then collect the function results.
a.product(b) => [[1, 3], [1, 4], [2, 3], [2, 4]]
So you can use map
or collect
to get the results. They are different names for the same method.
a.product(b).collect { |x, y| f(x, y) }
Find all permutations of Ruby array of arrays
What you need is the cartesian product. Something like:
[1].product([2,3],[4,5],[6]) # => [[1, 2, 4, 6], [1, 2, 5, 6], [1, 3, 4, 6], [1, 3, 5, 6]]
Find all the possible permutations using Ruby and recursion
To see what the difficulty may be, let's try it with an even simpler example:
string = "ab"
Your desired result is ["ab", "ba"]
. Let's see what you get:
string.size #=> 2
so we don't return when
return [string] if string.size < 2
#=> return ["ab"] if "ab".size < 2
is executed.
Next we calculate:
chr = string.chars.first #=> "a"
Notice that a more direct way of making this calculation is as follows:
chr = string[0] #=> "a"
or, better, using String#chr,
chr = string.chr #=> "a"
The latter illustrates why chr
is not the best choice for the variable name.
Next
perms = permutation(string[1..-1])
#=> = permutation("b")
I will now indent the return values to emphasize that we are calling permutation
a second time. permuation
's argument is:
string #=> "b"
Now when we execute:
return [string] if string.size < 2
#=> return ["b"] if "b".size < 2
we return ["b"]
, so (back to original call to permutation
):
perms = ["b"]
to go with chr => "a"
, calculated earlier. Next:
result = []
for perm in perms
for i in (0..perm.size)
result << (perm[0..i] + chr + perm[i..-1])
end
end
As perms
contains only the single element "b"
, the two for
loops simplify to:
for i in (0.."b".size)
result << ("b"[0..i] + "a" + "b"[i..-1])
end
which is:
for i in (0..1)
result << ("b"[0..i] + "a" + "b"[i..-1])
end
Notice that "b"[0..0]
, "b"[0..1]
and "b"[0..-1]
all equal "b"[0]
, which is just "b"
, and "b"[1..-1] #=> ''
. Therefore, when i => 0
, we execute:
result << ("b"[0..0] + "a" + "b"[0..-1])
#=> result << ("b" + "a" + "b")
#=> result << "bab"
and when i => 1
:
result << ("b"[0..1] + "a" + "b"[1..-1])
#=> result << ("b" + "a" + "")
#=> result << "ba"
so:
result => ["bab" + "ba"]
which clearly is not what you want.
What you need to do is is change the double for
loops to:
for perm in perms
result << chr + perm
for i in (1..perm.size-1)
result << (perm[0..i-1] + chr + perm[i..-1])
end
result << perm + chr
end
which could be written more compactly by employing the method String#insert:
for perm in perms
for i in (0..perm.size)
result << perm.dup.insert(i,chr)
end
end
which you would normally see written like this:
perms.each_with_object([]) do |perm, result|
(0..perm.size).each { |i| result << perm.dup.insert(i,chr) }
end
Notice that we have to .dup
the string before sending insert
, as insert
modifies the string.
Doing it like this, you don't need result = []
. Neither do you need return result
, as parms.each_with_object
returns result
and if there is no return
statement, the method returns the last quantity calculated. Also, you don't need the temporary variable perms
(or ch
, if desired).
Putting this altogether, we have:
def permutation(string)
return [string] if string.size < 2
ch = string[0]
permutation(string[1..-1]).each_with_object([]) do |perm, result|
(0..perm.size).each { |i| result << perm.dup.insert(i,ch) }
end
end
Let's try it:
permutation("ab")
#=> ["ab", "ba"]
permutation("abc")
#=> ["abc", "bac", "bca", "acb", "cab", "cba"]
permutation("abcd")
#=> ["abcd", "bacd", "bcad", "bcda", "acbd", "cabd",
# "cbad", "cbda", "acdb", "cadb", "cdab", "cdba",
# "abdc", "badc", "bdac", "bdca", "adbc", "dabc",
# "dbac", "dbca", "adcb", "dacb", "dcab", "dcba"]
Eki, which one are you in the picture?
Ruby: Permutation on an Array
Please test in detail before use:
x = [1,0]
n = 3
def perm(a, n)
l = a.length
(l**n).times do |i|
entry = []
o = i
n.times do
v = o % l
entry << a[v]
o /= l
end
yield(i, entry)
end
end
perm(x, n) do |i, entry|
puts "#{i} #{entry.reverse.inspect}"
end
prints
0 [0, 0, 0]
1 [0, 0, 1]
2 [0, 1, 0]
3 [0, 1, 1]
4 [1, 0, 0]
5 [1, 0, 1]
6 [1, 1, 0]
7 [1, 1, 1]
Related Topics
Selenium Webdriver Take Screenshot of Viewport Only
In Ruby, How to Know in the Console What a Method Does
How to Mimic Browser X509 Client Certificate Verification Without Access to Http Layer
Ruby, Value Bucketing, Beautify Code
How to Convert a Large Gem to Standalone Rails App
Mongomapper Association Skips Duplicates
How to Remove Devise Password Resetting During Email Confirmation
Check If a Table Exists in Rails
Get File Name and Extension in Ruby
Shoulda/Rspec Matchers - Conditional Validation
Connection Refused Using Sunspot and Solr in Rails
Cannot Require 'Nokogiri' in Rails (But Works in Irb)
Replacing an Element in Nested Array Ruby
Make a Ruby Script with Text Io Double Clickable Executable File
Rally Ruby Toolkit: How to Get Url of Portfolio Item's State