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]]