How to declare an empty 2-dimensional array in Ruby? - arrays

Can somebody please tell me how to declare a new instance of a 2-dimensional array?
Most of the languages use something like:
array = Array.new[2][2]
I don't know how to do it in Ruby.

You can do:
width = 2
height = 3
Array.new(height){Array.new(width)} #=> [[nil, nil], [nil, nil], [nil, nil]]

To declare 2d array in ruby, Use following syntax with initialization value
row, col, default_value = 5, 4, 0
arr_2d = Array.new(row){Array.new(col,default_value)}
=> [[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0]]
We can do any level of nesting, like for 3d array(5 x 4 x 2): you can pass block to initialize array in most inner Array
z = 2
arr_3d = Array.new(row){Array.new(col){Array.new(z){|index| index}}}
=> [[[0, 1], [0, 1], [0, 1], [0, 1]],
[[0, 1], [0, 1], [0, 1], [0, 1]],
[[0, 1], [0, 1], [0, 1], [0, 1]],
[[0, 1], [0, 1], [0, 1], [0, 1]],
[[0, 1], [0, 1], [0, 1], [0, 1]]]
Now, you can access its element using [] operator like arr_2d[0][1], actually its array of arrays

You could also initialize passing a value:
Array.new(3) { Array.new(3) { '0' } }
Output:
[
["0", "0", "0"],
["0", "0", "0"],
["0", "0", "0"]
]

You can declare a multidimensional array in Ruby with:
Array.new(Number_of_ROWs){Array.new(Number_of_COLUMNs)}
How To Use This Syntax
Let us understand it by using above example i.e. array = Array.new[2][2].
So, in this example we've to declare an empty multidimensional array with 2 rows and 2 column.
Let us start implementing the our syntax now,
array = Array.new(2){Array.new(2)}
Now you've an array with 2 rows and 2 column with nil values.
Now the array variable contains [[nil, nil], [nil, nil]] which is consider as an empty multidimensional array or nil value multidimensional array.

simply:
array = Array.new(8,Array.new(8))

Related

Transforming an array using Ruby

how would I transform this array :
[["10"], ["20"], ["30"], ["40"], ["21"], ["31"], ["41"], ["32"], ["42"], ["43"]]
into this array
[[1, 0], [2, 0], [3, 0], [4, 0], [2, 1], [3 1,], [4, 1], [3, 2], [4, 2], [4, 3]]
Ideally in the most beginner friendly version possible please.
I'm failing to iterate through the array thoroughly and use the correct methods in the correct order.
If the input is always as in your example (an array of arrays, where every array has a single element which is a string) then you can map to get the chars and then map that result to get them as integers;
[["10"], ["20"], ["30"], ["40"], ["21"], ["31"], ["41"], ["32"], ["42"], ["43"]]
.map { |str, _| str.chars.map(&:to_i) }
# [[1, 0], [2, 0], [3, 0], [4, 0], [2, 1], [3, 1], [4, 1], [3, 2], [4, 2], [4, 3]]

How can I arrange k elements by frequency in Decreasing Order in Ruby?

Given the array (array) [1, 1, 2, 2, 2, 3] this method should return (new_array)
[2, 2, 2, 1, 1, 3]
Heres what I have tried so far
Converted array into hash
Key being the element and value being the count
How do I recreate the array again to match new_array?
Here's one way:
array = [1,1,2,2,2,3]
array.tally # This is the bit you did already. Note that this uses the new ruby 2.7 method. You get: {1=>2, 2=>3, 3=>1}
.sort_by {|k, v| -v} # Now we have: [[2, 3], [1, 2], [3, 1]]
.flat_map { |element, count| Array.new(count, element) }
# And that gives the final desired result of:
[2, 2, 2, 1, 1, 3]
Or another variant, along the same lines:
array.tally # {1=>2, 2=>3, 3=>1}
.invert # {2=>1, 3=>2, 1=>3}
.sort # [[1, 3], [2, 1], [3, 2]]
.reverse # [[3, 2], [2, 1], [1, 3]]
.flat_map { |element, count| [element] * count }
Or, here's something completely different:
array.sort_by { |x| -array.count(x) }
Here is another one:
array = [1,1,2,2,2,3]
p array.group_by(&:itself).values.sort_by(&:size).flatten
def sort_chunks_by_length(arr)
arr.slice_when(&:!=).sort_by { |a| -a.size }.flatten
end
sort_chunks_by_length [1,1,2,2,2,3]
#=> [2, 2, 2, 1, 1, 3]
sort_chunks_by_length [1,1,2,2,2,1,3,3]
#=> [2, 2, 2, 1, 1, 3, 3, 1]
I have assumed that for the second example the desired return value is as shown, as opposed to:
#=> [2, 2, 2, 1, 1, 1, 3, 3]
The steps for that example are as follows.
arr = [1,1,2,2,2,1,3,3]
enum = arr.slice_when(&:!=)
#=> #<Enumerator: #<Enumerator::Generator:0x00007ffd1a9740b8>:each>
This is shorthand for:
enum = arr.slice_when { |x,y| x!=y }
We can see the elements that will be generated by this enumerator by converting it to an array:
enum.to_a
#=> [[1, 1], [2, 2, 2], [1], [3, 3]]
Continuing,
a = enum.sort_by { |a| -a.size }
#=> [[2, 2, 2], [1, 1], [3, 3], [1]]
a.flatten
#=> [2, 2, 2, 1, 1, 3, 3, 1]
The operative line could be replaced by either of the following.
arr.chunk(&:itself).map(&:last).sort_by { |a| -a.size }.flatten
arr.chunk_while(&:==).sort_by { |a| -a.size }.flatten
See Enumerable#slice_when, Enumerable#sort_by, Enumerable#chunk and Enumerable#chunk_while.

Why is my enumeration stopping after first rejection in Ruby?

Desperate need of help. I am trying to remove arrays from and array of arrays, and I have hit a road block. Essentially, if the first value in the child-array doesn't exist in either position of any other child-arrays, then it should be deleted. (presume that the array will be sorted - cause it will be)
arr = [[0, 1], [2, 3], [4, 5]]
arr.each_with_index do |inside_array, index|
if !index.zero?
# arr.delete(arr[index]) if arr.select {|x| x.include?(inside_array[0])}.count < 2
# refactored
arr.reject! {|x| x.include?(inside_array[0])}
end
end
=> [[0, 1], [4, 5]]
# Why does it stop itterating/enumerating after the first deletion?
# Goal output is [[0, 1]] for this example
Similarly, an array such as [[0, 1], [2, 3], [1, 5]], should yield [[0, 1], [1, 5]]
-or -
[[0, 1], [2, 3], [0, 3]], should yield [[0, 1], [0, 3]]
You've tried to modify origin array. That's your problem.
In that cases you need to duplicate it like this:
arr = [[0, 1], [2, 3], [4, 5]]
arr.dup.each_with_index do |inside_array, index|
if !index.zero?
arr.reject! {|x| x.include?(inside_array[0])}
end
end
arr #=> [[0, 1]]
So just use dup
As for the second question (implementation of subarray removal), I suggest this refactoring:
def remove_subarray(arr)
arr.reject { |inside_array| (inside_array & arr.first).empty? }
end
remove_subarray([[0, 1], [2, 3], [4, 5]]) #=> [[0, 1]]
remove_subarray([[0, 1], [2, 3], [1, 5]]) #=> [[0, 1], [1, 5]]
remove_subarray([[0, 1], [2, 3], [0, 3]]) #=> [[0, 1], [0, 3]]

Finding index and size of consecutive repeated elements in an array

An array consists of 1, 2, and 0s. I am trying to identify the maximum repetition and its starting index within the array.
Example:
2 2 1 0 2 2 2 0 1 1
The method should accept an integer arguement, which can be one of the numbers 1 or 2
If we demonstrate these inputs on above array, the outputs would be:
find_duplicates(2)
=> 3,4
find_duplicates(1)
=> 2,8
where the first number indicates the size of the duplication, and second is the starting index of it.
I tried looping through the array and compare with arr[i+1] or arr[-1], but this is not the correct approach. Any help will be greatly appreciated.
Edit:
I had not pasted what I had tried at the time I asked the question, this is not something I would do if I could feel some confidence on the way I followed:
def find_status(arr,participant)
status = Array.new
#arr is a two dimensional array
for i in 0...arr.length do
current_line=arr[i]
cons=0
for j in 0...current_line.length do
#I worked on lots of if/else/case statements here, this is just one of them
if current_line[j] == participant
cons+=1 #count consecutive
if current_line[j]!=participant
cons=0
end
end
status[i] = cons
end
end
return status
end
def max_run(arr, target)
_,b = arr.each_with_index.
chunk { |n,_| n==target }.
select { |tf,_| tf==true }.
max_by { |_,a| a.size }
b ? [b.size, b.first.last] : nil
end
arr = [1,1,2,2,2,3,1,1,1,1,2,2,2,2,3,3]
max_run(arr,1) #=> [4, 6]
max_run(arr,2) #=> [4, 10]
max_run(arr,3) #=> [2, 14]
max_run(arr,4) #=> nil
For target = 2, the steps are as follows:
enum0 = arr.each_with_index
#=> #<Enumerator: [1, 1, 2, 2, 2, 3, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3]
# :each_with_index>
We can see the elements that will be generated by this enumerator by converting it to an array:
enum0.to_a
#=> [[1, 0], [1, 1], [2, 2], [2, 3], [2, 4], [3, 5], [1, 6], [1, 7], [1, 8],
# [1, 9], [2, 10], [2, 11], [2, 12], [2, 13], [3, 14], [3, 15]]
Continuing,
enum1 = enum0.chunk { |n,_| n==target }
#=> #<Enumerator: #<Enumerator::Generator:0x007f9beb9b0850>:each>
Carefully examine the return value here. You can think of enum1 as a "compound enumerator". It will generate the following values:
enum1.to_a
#=> [[false, [[1, 0], [1, 1]]], [true, [[2, 2], [2, 3], [2, 4]]],
# [false, [[3, 5], [1, 6], [1, 7], [1, 8], [1, 9]]],
# [true, [[2, 10], [2, 11], [2, 12], [2, 13]]], [false, [[3, 14], [3, 15]]]]
Continuing,
c = enum1.select { |tf,_| tf==true }
#=> [[true, [[2, 2], [2, 3], [2, 4]]],
# [true, [[2, 10], [2, 11], [2, 12], [2, 13]]]]
_,b = c.max_by { |_,a| a.size }
#=> [true, [[2, 10], [2, 11], [2, 12], [2, 13]]]
b #=> [[2, 10], [2, 11], [2, 12], [2, 13]]
b ? [b.size, b.first.last] : nil
#=> [[2, 10], [2, 11], [2, 12], [2, 13]] ? [4, [2,10].last]
#=> [4, 10]
a = [2, 2, 1, 0, 2, 2, 2, 0, 1, 1]
longest_sequence =
a.each_index.select{|i| a[i] == 2}.chunk_while{|i, j| i.next == j}.max_by(&:length)
# => [4, 5, 6]
[longest_sequence.length, longest_sequence.first] # => [3, 4]
The solution below is likely most efficient since it is O(N). It walks through an array, collecting the chunks:
arr.each.with_index.reduce({idx:-1, i: -1, len: 0}) do |memo, (e, i)|
memo[:i] = i if memo[:i] == -1 && e == 2 # at the beginning of chunk
memo[:len], memo[:idx] = [i - memo[:i], memo[:i]] \
if memo[:i] >= 0 && i - memo[:i] > memo[:len] # save values if needed
memo[:i] = -1 unless e == 2 # reset index counter
memo
end.reject { |k, _| k == :i } # reject temporary index value
#⇒ {
# :idx => 4,
# :len => 3
# }
To use it as method, accepting a parameter; just wrap the code above with def find_duplicates number and substitute 2 with number in the code above. Yes, it returns hash instead of an array.

Sorting array by more than one condition

I have an array of points:
arr = [[2,0], [1,0], [2,1], [1,1]]
How would I sort the elements in descending and ascending orders by x first and then by y values of the similar x value?
max = [[2,1], [2,0], [1,1], [1,0]]
min = [[1,0], [1,1], [2,0], [2,1]]
.
min = arr.sort
# => [[1, 0], [1, 1], [2, 0], [2, 1]]
max = min.reverse
# => [[2, 1], [2, 0], [1, 1], [1, 0]]
If performance is an issue rather than simplicity, then the following can be used.
min = arr.sort_by(&:itself)
This is a good use case for Enumerable#sort_by.
For max:
arr.sort_by { |el| [-el[0], -el[1]] }
=> [[2, 1], [2, 0], [1, 1], [1, 0]]
For min:
arr.sort_by { |el| [el[0], el[1]] }
=> [[1, 0], [1, 1], [2, 0], [2, 1]]

Resources