I have a two-dimensional array of a bunch of strings, including some empty strings. I want to replace the empty strings with nil. How do I do this in Ruby?
Sample array:
[['cat','','dog',''],['','','fish','','horse']]
Desired output:
[['cat',nil,'dog',nil],[nil,nil,'fish',nil,'horse']]
[['cat','','dog',''],['','','fish','','horse']].map do |arr|
arr.map { |s| s unless s.empty? }
end
# => [["cat", nil, "dog", nil], [nil, nil, "fish", nil, "horse"]]
Related
If I do the following:
table = Array.new(
3,
Array.new(
3,
nil
)
)
# =>
[
[nil, nil, nil],
[nil, nil, nil],
[nil, nil, nil]
]
Now I would like to modify the value at index 2 in the second array, so I would do:
table[1][2] = 2.343
I would now expect to see:
# =>
[
[nil, nil, nil],
[nil, nil, 2.343],
[nil, nil, nil]
]
However what I'm getting is this:
[
[nil, nil, 2.343],
[nil, nil, 2.343],
[nil, nil, 2.343]
]
What am I not getting here?
PS: Running ruby 2.3
For fix with behavior, try next:
empty_table = Array.new(3) { Array.new(3) }
From array manual:
Note that the second argument populates the array with references to the same object. Therefore, it is only recommended in cases when you need to instantiate arrays with natively immutable objects such as Symbols, numbers, true or false.
you are essentially saying create an array with three elements, and put this element (the new array) in each space. The element you are putting in the first array, is just created once. The only way I know to do what you want is using a for loop to push as many new arrays into the first array as you need. something like this:
table = Array.new(1, Array.new(3, 0))
0..1.each do |i|
table.push(Array.new(3, 0)) #add two more arrays to the first dimension
end
How to remove the tailing nil/empty values in array?
I want to remove the tailing nil values in the following array,
So the array size may become 125, not 127
...
[123] "Conc_Net_LE_8_TDR_Long_Other",
[124] "Conc_Net_LE_8_TDR_Short_Other",
[125] "Contract_Units",
[126] nil,
[127] nil,
["foo", nil, ""].grep(/./)
# => ["foo"]
You can do
new_array = array.compact.delete("")
#compact will remove all nil objects, and using #delete, you can delete all empty string object(""). You can also do :
array.delete_if { |elem| elem.nil? || elem.empty? }
Use Array#compact, or the bang version compact! to modify the called object to remove the nil elements.
> arr = [1, nil]
> arr.compact
=> [1]
To remove nil and empty you can use Array#reject or also the bang version reject!
arr = [1, nil, ""]
arr.reject { |i| i.to_s.empty? }
=> [1]
If you are interested to remove only the tailing nil and empty sequence, maybe you can do something like this
array = ["1","2","3",nil," ","4",nil,nil, ""]
rev = array.reverse
while rev[0] == nil or is_empty_sequence?(rev[0])
rev.shift
end
p rev.reverse #Output -> ["1","2","3",nil," ","4"]
where is_empty_sequence? is a method where you declared what are the empty sequence.
I have built a presenter class whose only job is to convert a given array into a string. I am test driving the solution, so I started with "[nil, nil, nil]" but each nil will eventually be replaced with letter. That functionality is being handled by another class.
I am trying now to build an interface whose only job is to convert that string back to an array. So I will need to convert e.g. "[\"a\", \"b\", nil]" back to ["a", "b", nil]. But I am stuck.
For example, I'd like to convert
"[nil, nil, nil]"
to
[nil, nil, nil]
How could I do it?
Just use:
eval(string)
eval("[nil, nil, nil]")
Caution:
This is a very insecure method and you have to use it only if you are completely sure that the string contains a SAFE array..
I am guessing that you are producing the string yourself on one side, for example:
arr = [nil, nil, nil]
str = arr.inspect
#=> "[nil, nil, nil]"
Whereas I would advise you to serialize the array using a format such as JSON, YAML or Ruby's built in Marshalling library.
JSON
require 'json'
arr = [nil, nil, nil]
str = JSON.dump(arr)
#=> "[null,null,null]"
JSON.load(str)
#=> [nil, nil, nil]
YAML
require 'yaml'
arr = [nil, nil, nil]
str = YAML.dump(arr)
#=> "---\n- \n- \n- \n"
YAML.load(str)
#=> [nil, nil, nil]
Marshal
arr = [nil, nil, nil]
str = Marshal.dump(arr)
#=> "\x04\b[\b000"
Marshal.load(str)
#=> [nil, nil, nil]
I'm experiencing the following. I expect only the first sub-element of the first sub array to be assigned "x", not the first element of each sub array. Can anyone explain this behaviour, and perhaps how to work around it? (Note that this may well be expected behaviour, but if it is, it contradicts my expectations.)
x = Array.new(3, Array.new(5))
# => [[nil, nil, nil, nil, nil], [nil, nil, nil, nil, nil], [nil, nil, nil, nil, nil]]
x[0][0] # => nil
x[0][0] = "x"
x
# => [["x", nil, nil, nil, nil], ["x", nil, nil, nil, nil], ["x", nil, nil, nil, nil]]
workaround is :
x = Array.new(3) { Array.new(5) }
x[0][0] = 'a'
x # => [["a", nil, nil, nil, nil], [nil, nil, nil, nil, nil], [nil, nil, nil, nil, nil]]
new(size) {|index| block }
Here an array of the given size is created. Each element in this array is created by passing the element’s index to the given block and storing the return value.
Read also Common gotchas
When sending the second parameter, the same object will be used as the value for all the array elements. Since all the Array elements store the same array Array.new(5), changes to one of them will affect them all.
If multiple copies are what you want, you should use the block version which uses the result of that block each time an element of the array needs to be initialized, as I did above.
2d_array = Array.new(rows) { Array.new(columns) }
I'm pretty new to Ruby.
I need to extend Array and I need my class to represent bidimensional arrays.
I've done this:
class MyExtension < Array
def initialize(n)
super(n, Array.new(n, nil))
self[0][0] = "hello"
end
end
This looks theoretically right to me, but when I do:
p MyExtension.new(2)
I get
[["hello", nil], ["hello", nil]]
instead of the expected:
[["hello", nil], [nil, nil]]
What am I getting wrong?
That is a common mistake a beginner often makes. If you do super(n, Array.new(n, nil)), then Array.new(n, nil) will be evaluated only once, giving that same array (same object id) for each row. Since all the rows would be repetition of the same array, modifying one row by self[0][0] = "hello" would change all the other rows.
Instead, do
class MyExtension < Array
def initialize(n)
super(n){Array.new(n, nil)}
self[0][0] = "hello"
end
end
MyExtension.new(2) # => [["hello", nil], [nil, nil]]