Ruby Grouping nested array - ruby

how from this:
[
["1", "className", "Connection"],
["2", "className", "Connection"],
["1", "connectorId", "100"],
["2", "connectorId", "100"],
["1", "part_1", "side_1"],
["2", "part_1", "side_1"],
["1", "part_2", "bottomPanel_1"],
["2", "part_2", "bottomPanel_1"],
["1", "transformation", nil],
["2", "transformation", nil]
]
resive something like this:
[
[["1", "className", "Connection"],
["1", "connectorId", "100"],
["1", "part_2", "bottomPanel_1"],
["1", "part_1", "side_1"],
["1", "transformation", nil]],
[["2", "part_1", "side_1"],
["2", "className", "Connection"],
["2", "connectorId", "100"],
["2", "part_2", "bottomPanel_1"],
["2", "transformation", nil]]
]
I need to group nested arrays by first element.
thanks in advance.

Give a your array, try this
a.group_by(&:first).values
=> [
[["1", "className", "Connection"],
["1", "connectorId", "100"],
["1", "part_1", "side_1"],
["1", "part_2", "bottomPanel_1"],
["1", "transformation", nil]],
[["2", "className", "Connection"],
["2", "connectorId", "100"],
["2", "part_1", "side_1"],
["2", "part_2", "bottomPanel_1"],
["2", "transformation", nil]]
]

Ruby's Enumerable module has all kinds of goodies built into it, and group_by does very close to what you want.
arr.group_by { |x| x[0] } # Assuming your input array is called arr
This results in a dictionary where the keys are the groupings (i.e. the first elements of the inner arrays) and the values are the lists of elements in that group. That is,
{
"1" => [
["1", "className", "Connection"],
["1", "connectorId", "100"],
["1", "part_1", "side_1"],
["1", "part_2", "bottomPanel_1"],
["1", "transformation", nil]
],
"2" => [
["2", "className", "Connection"],
["2", "connectorId", "100"],
["2", "part_1", "side_1"],
["2", "part_2", "bottomPanel_1"],
["2", "transformation", nil]
]
}
If all you want are the groupings, not the keys, then we can just do
arr.group_by { |x| x[0] }.values
which gives you exactly the result you want.

While the other answers are both correct, your end result still looks cumbersome to deal with. I would recommend taking this a step further so that the resulting object is easier to utilize
a =[
["1", "className", "Connection"],
["2", "className", "Connection"],
["1", "connectorId", "100"],
["2", "connectorId", "100"],
["1", "part_1", "side_1"],
["2", "part_1", "side_1"],
["1", "part_2", "bottomPanel_1"],
["2", "part_2", "bottomPanel_1"],
["1", "transformation", nil],
["2", "transformation", nil]
]
# shift will mutate the inner Arrays
# if this does not matter you can remove map(&:dup)
b = a.map(&:dup).group_by(&:shift).transform_values(&:to_h)
#=> {"1"=>{
# "className"=>"Connection",
# "connectorId"=>"100",
# "part_1"=>"side_1",
# "part_2"=>"bottomPanel_1",
# "transformation"=>nil},
# "2"=>{
# "className"=>"Connection",
# "connectorId"=>"100",
# "part_1"=>"side_1",
# "part_2"=>"bottomPanel_1",
# "transformation"=>nil}
# }
Now the resulting Object is a Hash which will make accessing the data much easier. e.g. to access 1's connectorId
Your Result: b[0][1][2] or b.dig(0,1,2)
Hash Result: b["1"]["connectorId"]
Turning the results into a Hash will also allow for order independence in the event that the order of a is not as determinate as it is in the post.

Related

Convert Hash Into And Array Of Strings

{"offer:manage_all"=>["0", "1"], "offer:index"=>["0"], "offer:new"=>["0"], "offer:show"=>["0"], "offer:create"=>["0"], "offer:update"=>["0"], "offer:destroy"=>["0"], "job:manage_all"=>["0", "1"], "job:index"=>["0", "1"], "job:new"=>["0"], "job:create"=>["0"], "job:edit"=>["0"], "job:update"=>["0"], "job:destroy"=>["0"], "user:manage_all"=>["0", "1"], "user:index"=>["0"], "user:new"=>["0"], "user:create"=>["0"], "user:edit"=>["0"], "user:update"=>["0"], "user:destroy"=>["0"], "account_access:manage_all"=>["0", "1"], "role:manage_all"=>["0", "1"], "role:index"=>["0"], "role:new"=>["0"], "role:create"=>["0"], "role:edit"=>["0"], "role:update"=>["0"], "role:destroy"=>["0"], "welcome_package:manage_all"=>["0", "1"]}
I need to convert this hash into a string.
If the key has a value of 1 the key needs to be pushed to a an array.
The above will has will need to equal this because they are the keys with a value that includes 1.
["offer:manage_all", "job:manage_all", "job:index", "account_access:manage_all", "role:manage_all", "welcome_package:manage_all"]
Thank you in advance.
Given the hash:
h = {"cat"=>["0", "1"], "dog"=>["0"], "pig"=>["0", "1"], "owl"=>["0"], "hen"=>["0", "1"] }
I would write
h.keys.select { |k| h[k].include? "1" }
#=> ["cat", "pig", "hen"]
try method select and keys
hash = {"offer:manage_all"=>["0", "1"], "offer:index"=>["0"], "offer:new"=>["0"], "offer:show"=>["0"], "offer:create"=>["0"], "offer:update"=>["0"], "offer:destroy"=>["0"], "job:manage_all"=>["0", "1"], "job:index"=>["0", "1"], "job:new"=>["0"], "job:create"=>["0"], "job:edit"=>["0"], "job:update"=>["0"], "job:destroy"=>["0"], "user:manage_all"=>["0", "1"], "user:index"=>["0"], "user:new"=>["0"], "user:create"=>["0"], "user:edit"=>["0"], "user:update"=>["0"], "user:destroy"=>["0"], "account_access:manage_all"=>["0", "1"], "role:manage_all"=>["0", "1"], "role:index"=>["0"], "role:new"=>["0"], "role:create"=>["0"], "role:edit"=>["0"], "role:update"=>["0"], "role:destroy"=>["0"], "welcome_package:manage_all"=>["0", "1"]}
keys = hash.select{ |key,val| val.include? "1" }.keys
#=> ["offer:manage_all", "job:manage_all", "job:index", "user:manage_all", "account_access:manage_all", "role:manage_all", "welcome_package:manage_all"]

joining multidimensional array Into pairs Ruby

For this program I'm making i need to join together some arrays in a multidimensional array:
What the array is:
[["2", "2"]["0", "9"]["2", "2"]["2", "7"]["1", "7"]["0", "8"]["0", "1"]
["0", "9"]]
And I want it to become like this:
["22", "09", "22", "27", "17", "08", "01", "09"]
Sorry if this is a really dumb question but if someone can help me I would be very happy, and if it is impossible to do this, then please tell me.
Thanks.
Try this:
multi_dimensional_array = [["2", "2"], ["0", "9"], ["2", "2"], ["2", "7"], ["1", "7"], ["0", "8"], ["0", "1"], ["0", "9"]]
multi_dimensional_array.map(&:join)
map iterates over the entries in your array and returns a copy of the array with modified entries.
&:join sends join to every member of the iteration by converting the symbol to a block using Symbol#to_proc: You can read it as if it expands to:
->(entry){ entry.send(:join) }
Generally the pattern is:
list = [["2", "2"],["0", "9"],["2", "2"],["2", "7"],["1", "7"],["0", "8"],["0", "1"],["0", "9"]]
# For each item in the list, transform it...
list.collect do |entry|
# ...by joining the bits together into a single string.
entry.join
end

Produce all permutations of a number's digits

I've recently solved a problem, which takes a 3-4 digit number, such as 1234, (as well as some greater numbers) and returns a sorted array of ALL the possible permutations of the numbers [1234, 1432, 4213, 2431, 3412, 3214, etc.]
I don't like my solution, because it used .times to add the numbers to the array, and thus is still fallible, and furthermore ugly. Is there a way that the numbers could be added to the array the perfect number of times, so that as soon as all the possible shufflings of the numbers have been reached, the program will stop and return the array?
def number_shuffle(number)
array = []
number = number.to_s.split(//)
1000.times{ array << number.shuffle.join.to_i}
array.uniq.sort
end
Do as below using Array#permutation:
>> a = 1234.to_s.chars
=> ["1", "2", "3", "4"]
>> a.permutation(4).to_a
=> [["1", "2", "3", "4"],
["1", "2", "4", "3"],
["1", "3", "2", "4"],
["1", "3", "4", "2"],
["1", "4", "2", "3"],
["1", "4", "3", "2"],
["2", "1", "3", "4"],
["2", "1", "4", "3"],...]
Your modified method will be :
def number_shuffle(number,size)
number.to_s.chars.permutation(size).to_a
end
For your method it will be:
def number_shuffle(number)
a = number.to_s.chars
a.permutation(a.size).to_a.map { |b| b.join.to_i }
end
p number_shuffle 123 # => [123, 132, 213, 231, 312, 321]

Ruby Nested Array

I have a nested array that looks like this:
#nested = [
['1','2','3'],
['1','5','9'],
['1','4','7'],
['3','5','7'],
['3','6','9'],
['7','8','9'],
['4','5','6'],
['2','5','8']
]
I'd like to take a user input of any integer (that 1..9) and find every array that has that input integer.
Not sure how to do it.
Use select:
num_to_search = "9"
#nested.select do |array|
array.include? num_to_search
end
#=> [["1", "5", "9"], ["3", "6", "9"], ["7", "8", "9"]]

How to combination/permutation in ruby?

I've this familiar question that looks like permutation/combination of the Math world.
How can I achieve the following via ruby?
badges = "1-2-3"
badge_cascade = []
badges.split("-").each do |b|
badge_cascade << b
end
Gives: => ["1", "2", "3"]
But I want it to be is:
=> ["1", "2", "3",
"1-2", "2-3", "3-1", "2-1", "3-2", "1-3",
"1-2-3", "2-3-1", "3-1-2"]
Functional approach:
bs = "1-2-3".split("-")
strings = 1.upto(bs.size).flat_map do |n|
bs.permutation(n).map { |vs| vs.join("-") }
end
#=> ["1", "2", "3", "1-2", "1-3", "2-1", "2-3", "3-1", "3-2", "1-2-3", "1-3-2", "2-1-3", "2-3-1", "3-1-2", "3-2-1"]
You ned to use Array#permutation method in order to get all permutations:
arr = "1-2-3".split '-' # => ["1", "2", "3"]
res = (1..arr.length).reduce([]) { |res, length|
res += arr.permutation(length).to_a
}.map {|arr| arr.join('-')}
puts res.inspect
# => ["1", "2", "3", "1-2", "1-3", "2-1", "2-3", "3-1", "3-2", "1-2-3", "1-3-2", "2-1-3", "2-3-1", "3-1-2", "3-2-1"]
Let me explain the code:
You split string into array passing separator '-' to String#split method
You need all permutations of length 1, 2, 3. Range 1..arr.length represents all these lengths.
You collect an array of all permutations using Enumerable#reduce.
You will get array of arrays here:
[["1"], ["2"], ["3"], ["1", "2"], ["1", "3"], ["2", "1"], ["2", "3"], ["3", "1"], ["3", "2"], ["1", "2", "3"], ["1", "3", "2"], ["2", "1", "3"], ["2", "3", "1"], ["3", "1", "2"], ["3", "2", "1"]]
You transform all subarrays of this array into strings using Array#join with your '-' separator inside of Enumerable#map
Array#permutation(n) will give you all the permutations of length n as an Array of Arrays so you can call this with each length between 1 and the number of digits in badges. The final step is to map these all back into strings delimited with -.
badges = "1-2-3"
badges_split = badges.split('-')
permutations = []
(1..badges_split.size).each do |n|
permutations += badges_split.permutation(n).to_a
end
result = permutations.map { |permutation| permutation.join('-') }
Update: I think Alex's use of reduce is a more elegant approach but I'll leave this answer here for now in case it is useful.

Resources