Compact for array two dimensions in Ruby - ruby

As we know compact in Array, it works like this :
[ "a", nil, "b", nil, "c", nil ].compact
#=> [ "a", "b", "c" ]
Is there a function similar to do that for an array two dimentions ?
[[nil, nil], ["Prestation Standard", 1]].compact => [["Prestation Standard", 1]]

This would work:
ary = [[nil, nil], ["Prestation Standard", 1]]
ary.map(&:compact).reject(&:empty?)
#=> [["Prestation Standard", 1]]
map(&:compact) returns a new 2D array with all nil values removed from the inner arrays and reject(&:empty?) removes those that are empty.

Related

translate java 2d array into ruby

How would I write this java code into ruby:
String[] [] Score = new String [row] [col];
Score[rCount][cCount] = num;
I thought it would as simple as:
score=[]
score[rcount][ccount]=num
But I keep getting "undefined method `[]=' for nil:NilClass (NoMethodError)"
Sorry, I don't know java, but have a look at the class methods Array#new and Array::[], and the instance methods Array#[]= and Array#[]. Here are some examples that should answer your question (and other questions that may be sparked, hopefully):
Array.new #=> []
[] #=> [] # shorthand for above
a = Array.new(5) { [] } #=> [[], [], [], [], []]
a[0][0] = 2
a #=> [[2], [], [], [], []]
a[3][2] = 4
a #=> [[2], [], [], [nil, nil, 4], []]
a[1] << 1
a #=> [[2], [1], [], [nil, nil, 4], []]
a[1] << 2
a #=> [[2], [1, 2], [], [nil, nil, 4], []]
a[1] << 3 << 4
a #=> [[2], [1, 2, 3, 4], [], [nil, nil, 4], []]
a[2] << [4,5]
a #=> [[2], [1, 2, 3, 4], [[4, 5]], [nil, nil, 4], []]
a[4].concat([4,5])
a #=> [[2], [1, 2, 3, 4], [[4, 5]], [nil, nil, 4], [4, 5]]
a = Array.new(3) { Array.new(3) }
#=> [[nil, nil, nil], [nil, nil, nil], [nil, nil, nil]]
a[1][2] = 4
a #=> [[nil, nil, nil], [nil, nil, 4], [nil, nil, nil]]
We could also write the default as a second argument:
a = Array.new(3,[]) #=> [[], [], []]
but that can be problematic:
a[0][0] = 'cat'
a #=> [["cat"], ["cat"], ["cat"]]
as is:
a = Array.new(3,Array.new(2)) #=> [[], [], []]
#=> [[nil, nil], [nil, nil], [nil, nil]]
a[0][0] = 'cat'
a #=> [["cat", nil], ["cat", nil], ["cat", nil]]
since each element of a is the same array.
Note that Ruby provides a convenience for writing certain methods that is commonly referred to as "syntactic sugar". If, for example, you write a = [1,2,3], Ruby will interpret that as a = Array.[](1,2,3) (and you could write it that way), the class method being Array::[]. Similarly, if a equals [1,2,3], a[1] = 'cat' is decoded as a.[]=(1, 'cat') and a[1] #=> 'cat' is a.[](1). Similarly, h = {} translates to h = Hash.new and so on.
Note that Ruby does not have a concept of "multidimensional arrays". For more on that you may wish to see a comment a left on this question.
Firstly, ruby programmers use snake case. Capital letter is using for class names.
Secondly, your problem happens just because
score[rcount] == nil # true
If you want to have an access to second dimension elements you need to initialize line as array:
score[rcount] = []
Now you can set second dimension element
score[rcount][ccount] = num

Ruby - creating a grid

This is very basic, but can someone explain in plain in english what exactly is happening in this code?
3.times do |row_index|
board[row_index] = []
3.times do |column_index|
board[column_index] = []
board[row_index][column_index] = nil
end
end
end
I will first correct your code and then will show you how to improve it with increasing simplifications.
Presumably the array board is initialized before your code and, because of the extra end is probably in a method, we need:
def initialize_board(n, val)
board = Array.new(n)
n.times do |row_index|
board[row_index] = Array.new(n)
n.times do |column_index|
board[row_index][column_index] = val
end
end
board
end
initialize_board(3, nil)
#=> [[nil, nil, nil], [nil, nil, nil], [nil, nil, nil]]
You see that, to make the method more robust, I've made the board's size (n) and initialization value (val) variables. The method must return board, so we need board as the next-to-last line. (Because it is the last line of the method that is executed, return board is not needed.)
Firstly, since you have board[row_index] =..., board must be created as an array with n elements. That's what Array.new(n) does. Similarly, since you have board[row_index][column_index] =..., board[row_index] (for each value of row_index) must be created as an array with n elements:
board[row_index] = Array.new(n)
This works, but it's not very Ruby-like. Better would be to write:
def initialize_board(n, val)
board = []
n.times do |row_index|
row = []
n.times { |column_index| row << val } # or row.push(val)
board << row # or board.push(val)
end
board
end
initialize_board(3, nil)
#=> [[nil, nil, nil], [nil, nil, nil], [nil, nil, nil]]
Notice that board is initialized to an empty array, is then filled with rows, then board is returned. Similarly, row is initialized to an empty array, filled with copies of val and then appended to board. We can tighten that up by using Enumerable#each_with_object:
def initialize_board(n, val)
n.times.with_object([]) do |row_index, board|
board << n.times.with_object([]) { |column_index, row| row << val }
end
end
initialize_board(3, nil)
#=> [[nil, nil, nil], [nil, nil, nil], [nil, nil, nil]]
We can now use Array.new with a block to create each row with the default value:
def initialize_board(n, val)
n.times.with_object([]) do |row_index, board|
board << Array.new(n) { val }
end
end
initialize_board(3, nil)
#=> [[nil, nil, nil], [nil, nil, nil], [nil, nil, nil]]
and then do it again:
def initialize_board(n, val)
Array.new(n) { Array.new(n) { val } }
end
arr = initialize_board(3, nil)
#=> [[nil, nil, nil], [nil, nil, nil], [nil, nil, nil]]
There's one last thing I'd like to mention. Suppose we set:
arr[1][1] = 'cat'
Then
arr #=> [[nil, nil, nil], [nil, "cat", nil], [nil, nil, nil]]
as expected.
If, however, we had written:
def initialize_board(n, val)
Array.new(n, Array.new(n, val))
end
Then:
arr = initialize_board(3, nil)
#=> [[nil, nil, nil], [nil, nil, nil], [nil, nil, nil]]
arr[1][1] = 'cat'
arr #=> [[nil, "cat", nil], [nil, "cat", nil], [nil, "cat", nil]]
which clearly is not what you want.
Try this way in Ruby
Input n defined as size of n x n matrix
Example
if n = 3
Matrix size is 3 x 3
Code
n = gets.chomp.to_i
# Array('A'..'Z').sample is random value from A to Z
matrix = Array.new(n) { Array.new(n) { Array('A'..'Z').sample } }
Output
[["D", "A", "M", "V"], ["X", "Q", "A", "E"], ["P", "D", "L", "S"],
["V", "M", "P", "Z"]]

array[array.size..-1] doesn't return nil

I noticed a strange behavior when Range are used as Array subscript. (At least it's strange for me.)
a = [1,2,3]
=> [1, 2, 3]
a[3]
=> nil
a[3..-1]
=> []
a[4]
=> nil
a[4..-1]
=> nil
I thought a[3..-1] returns nil, but somehow it returns []. a[-3..-4] also returns [].
Could anyone explain why it returns [], when I use marginal values of range?
Because when range.begin == array.length, it always returns []. This is noted as a "special case" in the Ruby documentation:
a = [ "a", "b", "c", "d", "e" ]
# special cases
a[5] #=> nil
a[6, 1] #=> nil
a[5, 1] #=> []
a[5..10] #=> []

Remove nil and blank string in an array in Ruby

I am new to Ruby and stuck with this issue. Let's say I have an array like this:
arr = [1, 2, 's', nil, '', 'd']
and I want to remove nil and blank string from it, i.e. final array should be:
arr = [1, 2, 's', 'd']
I tried compact but it gives this:
arr.compact!
arr #=> [1, 2, 's', '', 'd'] doesn't remove empty string.
I was wondering if there's a smart way of doing this in Ruby.
You could do this:
arr.reject { |e| e.to_s.empty? } #=> [1, 2, "s", "d"]
Note nil.to_s => ''.
Since you want to remove both nil and empty strings, it's not a duplicate of How do I remove blank elements from an array?
You want to use .reject:
arr = [1, 2, 's', nil, '', 'd']
arr.reject { |item| item.nil? || item == '' }
NOTE: reject with and without bang behaves the same way as compact with and without bang: reject! and compact! modify the array itself while reject and compact return a copy of the array and leave the original intact.
If you're using Rails, you can also use blank?. It was specifically designed to work on nil, so the method call becomes:
arr.reject { |item| item.blank? }
I tend to do:
arr = [1, 2, 's', nil, '', 'd']
arr.reject(&:blank?)
returns:
=> [1, 2, "s", "d"]
arr.reject(&:blank?)
Just use this, no need to anything else.
compact_blank (Rails 6.1+)
If you are using Rails (or a standalone ActiveSupport), starting from version 6.1, there is a compact_blank method which removes blank values from arrays.
It uses Object#blank? under the hood for determining if an item is blank.
[1, 2, 's', nil, '', 'd'].compact_blank
# => [1, 2, 's', 'd']
[1, "", nil, 2, " ", [], {}, false, true].compact_blank
# => [1, 2, true]
Here is a link to the docs and a link to the relative PR.
A destructive variant is also available. See Array#compact_blank!.
You can also use - to remove all nil and '' elements:
arr -= [nil, '']
#=> [1, 2, "s", "d"]
Demonstration
Or compact and reject with shortcut (in case you are not using Rails where you can just use arr.reject(&:blank?) ):
arr = arr.compact.reject(&''.method(:==))
#=> [1, 2, "s", "d"]
Demonstration
You can use compact with reject
arr = [1, 2, 's', nil, '', 'd']
arr = [1, 2, 's', 'd']
arr = arr.compact.reject { |h| h == "" }
or
arr = arr.compact.delete_if { |h| h == "" }
The simplest and fast way of doing this is :
arr = [1, 2, 's', nil, '', 'd'] - [nil,'']
==> arr = [1, 2, 's', 'd']
You can use compact and delete_if method to remove nil and blank string in an array in Ruby
arr = [1, 2, 's', nil, '', 'd']
arr.compact!.delete_if{|arrVal| arrVal.class == String and arrVal.empty?}
=> [1, 2, "s", "d"]
try this out:
[1, 2, "s", nil, "", "d"].compact.select{|i| !i.to_s.empty?}
Note: I am considering the array might have string with white spaces in it.
You can do:
arr = [1, 2, 's', nil, ' ', 'd']
arr.reject{|a| a.nil? || (a.to_s.gsub(' ', '') == '') }
#=> [1, 2, "s", "d"]
or:
arr.reject{|a| a.nil? || (a.to_s.gsub(' ', '').empty?) }
#=> [1, 2, "s", "d"]
or if you want to update arr object itself then:
arr.reject!{|a| a.nil? || (a.to_s.gsub(' ', '') == '') } # notice the ! mark, it'll update the object itself.
p arr #=> [1, 2, "s", "d"]
Hope this will work for your case :
arr = [1, 2, 's', nil, '', 'd']
arr.select{|x| x.to_s!="" }
I would probably add .strip to eliminate potential whitespace headaches (assuming its not a rails app).
array = [1, 2, "s", nil, " ", "d", "\n"]
array.reject!{|a| a.nil? || (a.to_s.strip.empty?) }
#=> [1, 2, "s", "d"]

How can I push keys to an unsorted array?

I'm trying to create an array of the keys of an ordered hash. I want them to be listed in the same order in both the array and the hash. I have this hash.
h = { "a" => 3, "b" => 1, "c" = 4, "d" = 2 }
What I want is this array.
arr = ["b", "d", "a", "c"]
I have
h.sort_by { |k, v| v}
h.keys
but that returns the keys in alphabetical order. What can I do to keep them in the order of the sorted hash?
h.sort_by{|k,v| v} will give you [["b", 1], ["d", 2], ["a", 3], ["c", 4]], then use .map to get the key.
h.sort_by{|k,v| v}.map &:first
h = { "a" => 3, "b" => 1, "c" => 4, "d" => 2 }
p h.sort_by(&:last).map(&:first) #=> ["b", "d", "a", "c"]
You may try this also,
h = { "a" => 3, "b" => 1, "c" => 4, "d" => 2 }
Hash[h.sort_by{|k,v| v}].keys
#=> ["b", "d", "a", "c"]
This code
h.sort_by { |k,v| v}
h.keys
doesn't work because the sort_by method doesn't sort the original array, it returns a new sorted array, where each value is a (key, value) pair from the original hash:
[["b", 1], ["d", 2], ["a", 3], ["c", 4]]
If you're using Ruby 2.1.1, you can then just call to_h on the array, which will re-map the key/value pairs back into a hash:
h.sort_by { |k, v| v}.to_h.keys

Resources