Adding parameters to Array Product function in Ruby - arrays

So I've been scratching my head trying to find a solution to this.
I need a method that will take any number of arrays that I need to collect the product of.
1 array:
return [A, B, C] # => [A, B, C]
2 arrays:
return [A, B, C].product([1, 2, 3]) # => [[A, 1], [A, 2], [A, 3], [B, 1] ... [C, 3]]
3 arrays:
return [A, B, C].product([1, 2, 3,],[x, y, z]) # => [[A, 1, x], [A, 1, y], ... [C, 3, z]]
So my current solution is this case switch, which is functional but inconvenient.
case options.count
when 1
options[0].values
when 2
options[0].values.product(options[1].values)
when 3
options[0].values.product(options[1].values,
options[2].values)
when 4
options[0].values.product(options[1].values,
options[2].values,
options[3].values)
end
What I'm looking for is a method that procedurally or recursively returns the product of an unknown number of arrays. The output needs to be like the above arrays.
I've tried:
array = options[0].values
options.each_with_index do |option, i|
array = array.product(option.values) if i > 0
end
return array
But it returns:
[[[A, 1], x], [[A, 1], y], [[A, 1], z], [[A, 2], x], ... [[C, 3], z]]
Which groups the values incorrectly.

How about something like:
def multi_product(base, *args)
base.product(*args)
end
results:
multi_product(['A', 'B', 'C'])
# => [["A"], ["B"], ["C"]]
multi_product(['A', 'B', 'C'], [1, 2, 3])
# => [["A", 1], ["A", 2], ["A", 3], ["B", 1], ["B", 2], ["B", 3], ["C", 1], ["C", 2], ["C", 3]]
multi_product(['A', 'B', 'C'], [1, 2, 3], ['x', 'y', 'z'])
# => [["A", 1, "x"], ["A", 1, "y"], ["A", 1, "z"], ["A", 2, "x"], ["A", 2, "y"], ["A", 2, "z"], ["A", 3, "x"], ["A", 3, "y"], ["A", 3, "z"], ["B", 1, "x"], ["B", 1, "y"], ["B", 1, "z"], ["B", 2, "x"], ["B", 2, "y"], ["B", 2, "z"], ["B", 3, "x"], ["B", 3, "y"], ["B", 3, "z"], ["C", 1, "x"], ["C", 1, "y"], ["C", 1, "z"], ["C", 2, "x"], ["C", 2, "y"], ["C", 2, "z"], ["C", 3, "x"], ["C", 3, "y"], ["C", 3, "z"]]
multi_product(['A', 'B', 'C'], [1, 2, 3], ['x', 'y', 'z'], [4, 5, 6])
# => [["A", 1, "x", 4], ["A", 1, "x", 5], ["A", 1, "x", 6], ["A", 1, "y", 4], ["A", 1, "y", 5], ["A", 1, "y", 6], ["A", 1, "z", 4], ["A", 1, "z", 5], ["A", 1, "z", 6], ["A", 2, "x", 4], ["A", 2, "x", 5], ["A", 2, "x", 6], ["A", 2, "y", 4], ["A", 2, "y", 5], ["A", 2, "y", 6], ["A", 2, "z", 4], ["A", 2, "z", 5], ["A", 2, "z", 6], ["A", 3, "x", 4], ["A", 3, "x", 5], ["A", 3, "x", 6], ["A", 3, "y", 4], ["A", 3, "y", 5], ["A", 3, "y", 6], ["A", 3, "z", 4], ["A", 3, "z", 5], ["A", 3, "z", 6], ["B", 1, "x", 4], ["B", 1, "x", 5], ["B", 1, "x", 6], ["B", 1, "y", 4], ["B", 1, "y", 5], ["B", 1, "y", 6], ["B", 1, "z", 4], ["B", 1, "z", 5], ["B", 1, "z", 6], ["B", 2, "x", 4], ["B", 2, "x", 5], ["B", 2, "x", 6], ["B", 2, "y", 4], ["B", 2, "y", 5], ["B", 2, "y", 6], ["B", 2, "z", 4], ["B", 2, "z", 5], ["B", 2, "z", 6], ["B", 3, "x", 4], ["B", 3, "x", 5], ["B", 3, "x", 6], ["B", 3, "y", 4], ["B", 3, "y", 5], ["B", 3, "y", 6], ["B", 3, "z", 4], ["B", 3, "z", 5], ["B", 3, "z", 6], ["C", 1, "x", 4], ["C", 1, "x", 5], ["C", 1, "x", 6], ["C", 1, "y", 4], ["C", 1, "y", 5], ["C", 1, "y", 6], ["C", 1, "z", 4], ["C", 1, "z", 5], ["C", 1, "z", 6], ["C", 2, "x", 4], ["C", 2, "x", 5], ["C", 2, "x", 6], ["C", 2, "y", 4], ["C", 2, "y", 5], ["C", 2, "y", 6], ["C", 2, "z", 4], ["C", 2, "z", 5], ["C", 2, "z", 6], ["C", 3, "x", 4], ["C", 3, "x", 5], ["C", 3, "x", 6], ["C", 3, "y", 4], ["C", 3, "y", 5], ["C", 3, "y", 6], ["C", 3, "z", 4], ["C", 3, "z", 5], ["C", 3, "z", 6]]
What it does is take one required parameter (base) which responds to product and then the *args takes a variable number of other parameters and stores them in an array args. You can then use * to deconstruct an array back into an argument list, which is done inside the call to product(*args) so that (in the case of the second example) ends up looking like
['A', 'B', 'C'].product([1, 2, 3], ['x', 'y', 'z'])

Hope this helps
a = [["a", "b", "c"], ["d", "e", "f"], ["g", "h", "i"]]
a[0].product(*a[1..a.length])
#=> [["a", "d", "g"], ["a", "d", "h"], ["a", "d", "i"], ["a", "e", "g"], ["a", "e", "h"], ["a", "e", "i"], ["a", "f", "g"], ["a", "f", "h"], ["a", "f", "i"], ["b", "d", "g"], ["b", "d", "h"], ["b", "d", "i"], ["b", "e", "g"], ["b", "e", "h"], ["b", "e", "i"], ["b", "f", "g"], ["b", "f", "h"], ["b", "f", "i"], ["c", "d", "g"], ["c", "d", "h"], ["c", "d", "i"], ["c", "e", "g"], ["c", "e", "h"], ["c", "e", "i"], ["c", "f", "g"], ["c", "f", "h"], ["c", "f", "i"]]
# or
a.slice!(0).product(*a) #Note: this mutates array.
# or
a[0].product(*a.drop(1)) # suggested by Cary Swoveland

Related

Ruby merge a nested array based on inner array's first element [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 months ago.
Improve this question
I have a nested Ruby array:
array = [["id1", "Mike", "a", "aa"],
["id1", "Mike", "a", "bb"],
["id1", "Mike", "a", "cc"],
["id1", "Mike", "b", "aa"],
["id1", "Mike", "b", "bb"],
["id1", "Mike", "b", "cc"],
["id2", "Joe", "a", "aa"],
["id2", "Joe", "a", "bb"],
["id2", "Joe", "a", "cc"],
["id2", "Joe", "b", "aa"],
["id2", "Joe", "b", "bb"],
["id2", "Joe", "b", "cc"],
["id2", "Joe", "c", "aa"],
["id2", "Joe", "c", "bb"],
["id2", "Joe", "c", "cc"]]
I want to merge it based on the first element, with grouping as such:
result = [["id1", "Mike", ["a", "b"], ["aa", "bb", "cc"]],
["id2", "Joe", ["a", "b", "c"], ["aa", "bb", "cc"]]]
What's the best way to do this?
Code
result = array.group_by { |a| [a[0], a[1]] }.map do |k, v|
v.map { |id, name, v1, v2| [v1, v2] }.transpose.map(&:uniq).prepend(*k)
end
p result
Output
[["id1", "Mike", ["a", "b"], ["aa", "bb", "cc"]], ["id2", "Joe", ["a", "b", "c"], ["aa", "bb", "cc"]]]

Priority Sorting on a column Kusto Query

Scenario: Players can be marked with the status winner, tied, or loser. The priorities of the status is as such: If a player is ever "tied", they can't be a "loser", if they are ever a "winner", they can't be a "loser" or "tied". Table 1 has error rows recorded but the desired table should display the players and their up-to-date status and the timestamp of the most recent correct records. Is this something that is doable with Kusto? I can select the most recent by timestamp with the query below. I am unsure how to compare. I've started looking at the prev() function but I'm not certain this will do what I want in terms of comparing based on a priority. (https://learn.microsoft.com/en-us/azure/data-explorer/kusto/query/prevfunction)
let T1 = datatable(player:string, status:string, timestamp:datetime)
[
"A", "winner", datetime(2020-11-24 08:00),
"A", "winner", datetime(2020-11-24 10:00),
"B", "tied", datetime(2020-11-24 09:00),
"B", "tied", datetime(2020-11-24 11:00),
"B", "tied", datetime(2020-11-24 14:00),
"B", "loser", datetime(2020-11-24 15:00),
"C", "loser", datetime(2020-11-24 08:00),
"C", "loser", datetime(2020-11-24 10:00),
"C", "loser", datetime(2020-11-24 11:00),
"C", "loser", datetime(2020-11-24 13:00),
"C", "tied", datetime(2020-11-24 14:00),
"C", "winner", datetime(2020-11-24 15:00),
"D", "winner", datetime(2020-11-24 07:00),
"D", "winner", datetime(2020-11-24 11:00),
"D", "winner", datetime(2020-11-24 16:00),
"D", "tied", datetime(2020-11-24 21:00),
"E", "tied", datetime(2020-11-24 09:00),
"E", "tied", datetime(2020-11-24 11:00),
"E", "loser", datetime(2020-11-24 13:00),
"E", "tied", datetime(2020-11-24 18:00),
"F", "loser", datetime(2020-11-24 10:00),
"F", "loser", datetime(2020-11-24 11:00),
"F", "loser", datetime(2020-11-24 18:00),
"G", "loser", datetime(2020-11-24 11:00),
"G", "tied", datetime(2020-11-24 14:00),
"G", "loser", datetime(2020-11-24 16:00),
"G", "tied", datetime(2020-11-24 18:00),
"G", "loser", datetime(2020-11-24 21:00),
]
;
T1
| summarize arg_max(timestamp, *) by player
| order by player asc
result:
player| timestamp | status
_____________________________________________
A | 2020-11-24 10:00:00.0000000 | winner
B | 2020-11-24 15:00:00.0000000 | loser
C | 2020-11-24 15:00:00.0000000 | winner
D | 2020-11-24 21:00:00.0000000 | tied
E | 2020-11-24 18:00:00.0000000 | tied
F | 2020-11-24 18:00:00.0000000 | loser
G | 2020-11-24 21:00:00.0000000 | loser
H | 2020-11-24 21:00:00.0000000 | loser
final desired result table:
player| timestamp | status
_____________________________________________
A | 2020-11-24 10:00:00.0000000 | winner
B | 2020-11-24 14:00:00.0000000 | tied
C | 2020-11-24 15:00:00.0000000 | winner
D | 2020-11-24 16:00:00.0000000 | winner
E | 2020-11-24 18:00:00.0000000 | tied
F | 2020-11-24 18:00:00.0000000 | loser
G | 2020-11-24 18:00:00.0000000 | tied
H | 2020-11-24 09:00:00.0000000 | winner
If I understand your question correctly, the following could work.
Calculate the aggregated status per player, according the logic you've provided (using make_set() and array_index_of().
Find the max. timestamp per player/state, using a join
let T =
datatable(player: string, status: string, timestamp: datetime)
[
"A", "winner", datetime(2020-11-24 08:00),
"A", "winner", datetime(2020-11-24 10:00),
"B", "tied", datetime(2020-11-24 09:00),
"B", "tied", datetime(2020-11-24 11:00),
"B", "tied", datetime(2020-11-24 14:00),
"B", "loser", datetime(2020-11-24 15:00),
"C", "loser", datetime(2020-11-24 08:00),
"C", "loser", datetime(2020-11-24 10:00),
"C", "loser", datetime(2020-11-24 11:00),
"C", "loser", datetime(2020-11-24 13:00),
"C", "tied", datetime(2020-11-24 14:00),
"C", "winner", datetime(2020-11-24 15:00),
"D", "winner", datetime(2020-11-24 07:00),
"D", "winner", datetime(2020-11-24 11:00),
"D", "winner", datetime(2020-11-24 16:00),
"D", "tied", datetime(2020-11-24 21:00),
"E", "tied", datetime(2020-11-24 09:00),
"E", "tied", datetime(2020-11-24 11:00),
"E", "loser", datetime(2020-11-24 13:00),
"E", "tied", datetime(2020-11-24 18:00),
"F", "loser", datetime(2020-11-24 10:00),
"F", "loser", datetime(2020-11-24 11:00),
"F", "loser", datetime(2020-11-24 18:00),
"G", "loser", datetime(2020-11-24 11:00),
"G", "tied", datetime(2020-11-24 14:00),
"G", "loser", datetime(2020-11-24 16:00),
"G", "tied", datetime(2020-11-24 18:00),
"G", "loser", datetime(2020-11-24 21:00),
]
;
T
| summarize make_set(status) by player
| project player, status = case(array_index_of(set_status, "winner") > -1, "winner",
array_index_of(set_status, "tied") > -1, "tied",
"loser")
| join (
T
| summarize timestamp = max(timestamp) by player, status
) on player, status
| project player, timestamp, status

How To Check For 4 In Row In A Multidimensional Array (Ruby)

double_array = [
["0", "0", "0", "0", "0"],
["0", "0", "0", "0", "0"],
["0", "0", "0", "0", "0"],
["0", "0", "0", "0", "0"],
["0", "0", "0", "0", "0"],
]
Let's say the digits in this array change like so:
double_array = [
["1", "0", "0", "0", "0"],
["0", "1", "0", "0", "0"],
["0", "0", "1", "0", "0"],
["0", "0", "0", "1", "0"],
["0", "0", "0", "0", "0"],
]
How would I get be able to detect on that with some kind of if statement?
Something like if there are four in a row diagonally do [insert action here].
The same goes for if it were vertically or horizontally like so:
double_array = [
["1", "0", "0", "0", "0"],
["1", "0", "0", "0", "0"],
["1", "0", "0", "0", "0"],
["1", "0", "0", "0", "0"],
["0", "1", "1", "1", "1"],
]
I'd prefer the least complex way possible.
last_row_ndx = double_array.size-1
#=> 4
last_col_ndx = double_array.first.size-1
#=> 4
(0..last_row_ndx).each_with_object(Hash.new { |h,k| h[k] = [] }) do |i,h|
(0..last_col_ndx).each do |j|
v = double_array[i][j]
h[v] << [[i-1,j], [i,j]] if i > 0 && v == double_array[i-1][j]
h[v] << [[i,j-1], [i,j]] if j > 0 && v == double_array[i][j-1]
end
end
#=> {"1"=>[[[0, 0], [1, 0]], [[1, 0], [1, 1]], [[1, 0], [2, 0]],
# [[2, 0], [3, 0]], [[3, 0], [3, 1]], [[2, 2], [3, 2]],
# [[3, 1], [3, 2]], [[3, 2], [3, 3]]],
# "4"=>[[[0, 3], [1, 3]], [[1, 3], [2, 3]]],
# "0"=>[[[0, 4], [1, 4]], [[1, 4], [2, 4]], [[2, 4], [3, 4]],
# [[4, 0], [4, 1]], [[4, 1], [4, 2]], [[4, 2], [4, 3]],
# [[3, 4], [4, 4]], [[4, 3], [4, 4]]]}

turn array columns into rows ruby [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
I have an array of arrays called puzzle and I'm trying to return a new array with the first array consisting of
["a", "s", "i", "o", "s", "u", "z"]
Then the next array consisting of the array"s second index
["k", "o", "t", "t", "e", "r", "s"]
etc etc. What are some good ways to do this. I was thinking of using map and two counters but could not get them to operate or or increase at different times properly. Any help would be awesome. Thanks!
I want to return a new array from this puzzle:
puzzle = [
["a", "k", "f", "o", "x", "e", "s"],
["s", "o", "a", "w", "a", "h", "p"],
["i", "t", "c", "k", "e", "t", "n"],
["o", "t", "s", "d", "h", "o", "h"],
["s", "e", "x", "g", "s", "t", "a"],
["u", "r", "p", "i", "w", "e", "u"],
["z", "s", "b", "n", "u", "i", "r"]
]
Array#transpose is there for you:
puzzle = [
["a", "k", "f", "o", "x", "e", "s"],
["s", "o", "a", "w", "a", "h", "p"],
["i", "t", "c", "k", "e", "t", "n"],
["o", "t", "s", "d", "h", "o", "h"],
["s", "e", "x", "g", "s", "t", "a"],
["u", "r", "p", "i", "w", "e", "u"],
["z", "s", "b", "n", "u", "i", "r"]
]
puzzle.transpose
# => [["a", "s", "i", "o", "s", "u", "z"],
# ["k", "o", "t", "t", "e", "r", "s"],
# ["f", "a", "c", "s", "x", "p", "b"],
# ["o", "w", "k", "d", "g", "i", "n"],
# ["x", "a", "e", "h", "s", "w", "u"],
# ["e", "h", "t", "o", "t", "e", "i"],
# ["s", "p", "n", "h", "a", "u", "r"]]
class Array
def my_transpose!
size.times do |i|
0.upto(i) do |j| # iterate only through lower half
self[i][j], self[j][i] = self[j][i], self[i][j] # swap rows and cols
end
end
self # return the array itself
end
def my_transpose
dup.map(&:dup).my_transpose! # inner arrays are dup'ed, too
end
end
OR if you don't need a mutator....
.transpose method then pick the array you want with []
puzzle.transpose[0]
The [0] says give me the first result.
puzzle.transpose[0]
=> ["a", "s", "i", "o", "s", "u", "z"]
puzzle.transpose[1]
=> ["k", "o", "t", "t", "e", "r", "s"]

how to generate separate array of array in ruby based on one sub array value

I have an array of array as below:
a = [
["a", "v", 1], ["b", "w", 2], ["c", "x", 1], ["d", "y", 1],
["e", "z", 2], ["f", "one" , 3 ], ["g", "two" , 3 ], ["g", "one" , 4 ],
["f", "one" , 1 ], ["h", "one" , 5 ], ["f", "one" , 4 ],
# ...
]
Then , i expect the result as 5 different arrays
a1 = [ ["a", "v", 1],["c", "x", 1], ["d", "y", 1], ["f", "one" , 1 ] ]
a2 = [ ["b", "w", 2], ["e", "z", 2] ]
a3 = [ ["f", "one", 3], ["g", "two", 3] ]
a4 = [ ["g", "one", 4], ["f", "one", 4] ]
a5 = [ ["h", "one" , 5 ] ]
# ...
an = []
By doing the below code, i was able to sort it.
b = a.sort{|c,d|c[2] <=> d[2]}
How can i generate such a list.
Please help.Thanks in advance.
You could use partition:
a = [["a", "v", 1], ["b", "w", 2], ["c", "x", 1], ["d", "y", 1], ["e", "z", 2]]
a1, a2 = a.partition { |e| e[2] == 1 }
a1 #=> [["a", "v", 1], ["c", "x", 1], ["d", "y", 1]]
a2 #=> [["b", "w", 2], ["e", "z", 2]]
With more than 2 values, you could use group_by:
a = [
["a", "v", 1], ["b", "w", 2], ["c", "x", 1], ["d", "y", 1],
["e", "z", 2], ["f", "one" , 3 ], ["g", "two" , 3 ], ["g", "one" , 4 ],
["f", "one" , 1 ], ["h", "one" , 5 ], ["f", "one" , 4 ]
]
hash = a.group_by { |e| e[2] }
#=> { 1=>[["a", "v", 1], ["c", "x", 1], ["d", "y", 1], ["f", "one", 1]],
# 2=>[["b", "w", 2], ["e", "z", 2]],
# 3=>[["f", "one", 3], ["g", "two", 3]],
# 4=>[["g", "one", 4], ["f", "one", 4]],
# 5=>[["h", "one", 5]] }
To access the arrays, you can use hash[1], hash[2], etc. or you can assign them to variables:
a1, a2, a3, a4, a5 = hash.values_at(1, 2, 3, 4, 5)
a1 #=> [["a", "v", 1], ["c", "x", 1], ["d", "y", 1], ["f", "one", 1]]
a2 #=> [["b", "w", 2], ["e", "z", 2]]
a3 #=> [["f", "one", 3], ["g", "two", 3]]
a4 #=> [["g", "one", 4], ["f", "one", 4]]
a5 #=> [["h", "one", 5]]
Select would be the more readable option:
a.select do |v| v.third == 1 end
=> [["a", "v", 1], ["c", "x", 1], ["d", "y", 1]]

Resources