index of first non-nil value in array - ruby

What's the best way (in terms of both idiom and efficiency) to find the index of the first non-nil value in an array?
I've come up with first_non_null_index = array.index(array.dup.compact[0])...but is there a better way?

Ruby 1.9 has the find_index method:
ruby-1.9.1-p378 > [nil, nil, false, 5, 10, 20].find_index { |x| not x.nil? } # detect false values
=> 2
ruby-1.9.1-p378 > [nil, nil, false, 5, 10, 20].find_index { |x| x }
=> 3
find_index seems to be available in backports if needed in Ruby earlier than 1.8.7.

I think the best answer is in the question only.
Only change
first_non_null_index = (array.compact.empty?) "No 'Non null' value exist" : array.index(array.dup.compact[0]
Consider following example
array = [nil, nil, nil, nil, nil]
first_non_null_index = array.index(array.dup.compact[0]) #this will return '0' which is wrong

Related

How can I modify positions in a two dimensional array?

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

Passing not as a variable

I have two functions, each of which pulls items from an array while asking if a certain value is present or not. How could I create a method that can be flipped according to whether I'm asking if the value is present or not? The (!) below is what I'd like to pass as a variable.
ary.select{ |item| (!)item.my_value.nil? }
Is it possible to pass not to as a variable, somewhat like multiplying something by x where x could be 1 or -1?
I'll assume this is in general terms and you are wondering how to pass something that you can use in the implementation of your function to reverse it. Two strategies:
Ruby metaprogramming. You can use the BasicObject#! and Object#itself:
<
def values_from(array, post_mutator:)
array.select { |item| item.nil?.public_send(post_mutator) }
end
array = [1, nil, :b, nil, nil, 'foo']
values_from(array, post_mutator: :itself) # => [nil, nil, nil]
values_from(array, post_mutator: :!) # => [1, :b, "foo"]
Boolean algebra. Basically, you want to find an operation ., for which:
x . true = x
x . false = -x
All possibilities are:
true, true => true
false, false => true
false, true => false
true, false => false
Which obviously leaves the . to be equality. Therefore:
def values_from(array, switcher)
array.select { |item| item.nil? == switcher }
end
array = [1, nil, :b, nil, nil, 'foo']
values_from(array, true) # => [nil, nil, nil]
values_from(array, false) # => [1, :b, "foo"]
ndn's answer addresses how to do this with Ruby meta-programming, but I was hoping for something a little more elegant, so I ended up addressing this by adding to TrueClass and FalseClass (with a RoR initializer).
class TrueClass
def *(value)
!!value
end
end
class FalseClass
def *(value)
!value
end
end
So I can do the following, which feels a bit more natural.
def select_from_ary(present)
ary.select{ |item| present * item.my_value.nil? }
end
If you have a function called presence? that returns true when you checking the item is present and false when you're checking it's absent then:
ary.select{ |item| !!item.my_value == presence? }
Or as a method where the Boolean is passed in:
def get_value_presence(boolean presence?)
ary.select{ |item| !!item.my_value == presence? }
end
Splitting the truesand falses - that is what partition does:
array = [1, nil, :b, nil, nil, 'foo']
nils, non_nils = array.partition{|item| item.nil?} # or: array.partition(&:nil?)

In Ruby (1.9.3), why does nil respond to the comparison operator, `<=>`?

To me, a null type being compared to anything else (even another null type) is an undefined operation. Please correct me if I'm wrong there.
Under that assumption, the following makes sense to me:
nil.is_a? Comparable
=> false
nil.respond_to? :<=
=> false
nil.respond_to? :<
=> false
nil.respond_to? :>=
=> false
nil.respond_to? :>
=> false
However, nil does respond to the "spaceship" comparison operator:
nil.respond_to? :<=>
=> true
I cannot think of a situation where comparing nil is even meaningful, let alone practical. Why does nil have this behaviour?
nil in Ruby is a singleton instance of NilClass, which inherits from Object. Object implements <=>, which has its behavior defined as:
Returns 0 if obj and other are the same object or obj == other, otherwise nil. 0 means self is equal to other. 1 means self is bigger than other. Nil means the two values could not be compared.
(See the documentation)
Thus, nil <=> nil returns 0 (they are equivalent), but nil <=> anything_else returns nil, which means "could not be compared".
In Ruby, it is expected that all objects respond to <=> (including nil), but for objects for which it is a nonsensical or undefined operation, the return value is nil, which may then be handled as the calling code best sees fit. In the case of Enumerable's operations like #sort, it raises an exception:
[1, nil].sort
# => ArgumentError: comparison of NilClass with 1 failed
But it needn't necessarily; you could implement your own sort which just moves unsortable values to the beginning of the list:
[1, nil, 2, 3, nil].sort {|a, b| (a <=> b) || -1 }
# => [nil, nil, 1, 2, 3]
How useful is Object#<=> for nil? I think it's only limited by one's imagination.
Example #1
Here's a pedestrian example of how it can be useful. Suppose you wished to sort the array:
arr = [1,nil,3,nil,2]
with all the nils coming first, so it would return:
[nil, nil, 1, 2, 3]
As:
nil<=>nil #=> 0
and, for all non-nil objects a:
nil<=>x #=> nil
x<=>nil #=> nil
we can write:
arr.sort { |a,b| (a<=>b) ? a<=>b : a.nil? ? -1 : 1 }
#=> [nil, nil, 1, 2, 3]
Example #2
Now let's consider a second example that's much more interesting. Suppose we have oversold tickets to a theatre performance and must turn away some patrons, and give them refunds. The hash tickets shows what each person paid for their ticket:
ticket_holders = { 'bob'=>10, 'lucy'=>15, 'cher'=>5, 'arnold'=>12 }
We wish to minimize the refunds issued, but don't want negative publicity from turning away celebrities, given by the following:
celebrities = ['arnold', 'cher']
so we will give them the highest preference. We therefore wish to sort the ticket_holders by descending value, except we want key-value pairs whose key is in celebrities to come first. That is, we want the result to be:
['cher', 'arnold', 'lucy', 'bob']
or
['arnold', 'cher', 'lucy', 'bob']
Let's go for a general solution:
module Enumerable
def sort_by_nils_first
sort do |a,b|
av = yield(a)
bv = yield(b)
(av<=>bv) ? av<=>bv : av.nil? ? -1 : 1
end
end
end
which we apply thus:
ticket_holders.sort_by_nils_first { |name,price|
celebrities.include?(name) ? nil : -price }.map(&:first)
#=> ["arnold", "cher", "lucy", "bob"]
Considering alone the number of celebrities in the world, and how they are treated, I think this is a pretty useful method.
Applied to the earlier example, we obtain:
[1,nil,3,nil,2].sort_by_nils_first(&:itself)
#=> [nil, nil, 1, 2, 3]
where I've used Object#itself from v2.2.
sort_by_nils_first could of course be modified to return an Enumerator when no block is given, to make it comparable to Enumerable#sort_by.

How to remove the tailing nil/empty values in array

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.

Add nil object as an element of an array in Ruby

Can I have an array which has nil as a value in it?, e.g., [1, 3, nil, 23].
I have an array in which I assign nil like this array = nil, and then I want to iterate through it but I can't. The .each method fails saying nil class.
Is it possible to do this?
Use:
a = [nil]
Example:
> a = nil
=> nil
> a.each{|x|puts x}
NoMethodError: undefined method `each' for nil:NilClass
from (irb):3
from :0
> a= [nil]
=> [nil]
> a.each{|x|puts x}
nil
=> [nil]
I believe your problem lies in when you "assign nil" to the array
arr = []
arr = nil
Is this something like what you tried doing? In this case you do not assign nil to the array you assign nil to the variable arr, hence arr is now nil giving you errors concerning a "nil class"
Sure you can. You are probably trying to do something with the nil object without checking to see if it's nil? first.
C:\work>irb
irb(main):001:0> a = [1,2,nil,3]
=> [1, 2, nil, 3]
irb(main):003:0> a.each{|i|
irb(main):004:1* if i.nil? then
irb(main):005:2* puts ">NADA>"
irb(main):006:2> else
irb(main):007:2* puts i
irb(main):008:2> end
irb(main):009:1> }
1
2
>NADA>
3
=> [1, 2, nil, 3]
irb(main):010:0>
I think you're confusing adding an item to an array with assigning a value of nil to a variable.
Add an item to (the end of) an array (two ways):
array.push(item)
# or if you prefer
array << item
# works great with nil, too
array << nil
I'm assuming that the array already exists. If it doesn't, you can create it with array = [] or array = Array.new.
On the other hand, array = nil assigns nil to a variable that happens to be (misleadingly) named 'array'. If that variable previously pointed to an array, that connection is now broken.
You may be thinking of assignment with an index position, but array[4] = nil is very different from array = nil.
There is a problem with how you're storing the nil value in the array. Here is an example to show how arrays work:
a = nil
b = [nil]
c = []
c.push(nil)
# a is nil
# b is [nil]
# c is now [nil]
So, 'b' and 'c' both created an array with a nil attribute while 'a' just set a variable to nil (NOT an array).
With either 'b' or 'c', you should now be able to run .each without any problem
use Enumerable#map
ruby-1.8.7-p249 > [1,2,nil,4].map{|item| puts item}
1
2
nil
4
=> [nil, nil, nil, nil]
note that even though the return is nil for each item in the array, the original array is as it was. if you do something to operate on each item in the array, it will return the value of each operation. you can get rid of nils buy compacting it.
ruby-1.8.7-p249 > [1,2,nil,4].map{|item| item + 1 unless item.nil? }
=> [2, 3, nil, 5]
ruby-1.8.7-p249 > [1,2,nil,4].map{|item| item + 1 unless item.nil? }.compact
=> [2, 3, 5]

Resources