Add nil object as an element of an array in Ruby - 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]

Related

Ruby hash: return the first key value under which is not nil

Say I have a hash
hash = {a:1, b:false, c:nil}
& a series of keys somewhere: [:c, :b, :a]. Is there a Ruby idiom for returning such a key value under which != nil?
The obv
[:c, :b, :a].select {|key| hash[key] != nil}.first # returns :b
seems too long.
For that I think Enumerable#find might work:
find(ifnone = nil) { |obj| block } → obj or nil
find(ifnone = nil) → an_enumerator
Passes each entry in enum to block. Returns the first for which block
is not false. If no object matches, calls ifnone and returns its
result when it is specified, or returns nil otherwise.
If no block is given, an enumerator is returned instead.
In your case it'd return the first for which block is not nil:
p %i[c b a].find { |key| !{ a: 1, b: nil, c: nil }[key].nil? } # :a
p %i[c b a].find { |key| !{ a: 1, b: 1, c: nil }[key].nil? } # :b
If you want to filter elements with falsy values, you can use the following expressions.
keys = [:d, :c, :b, :a]
hash = { a: 1, b: nil, c: nil, d: 2 }
keys.select(&hash)
# => [:d, :a]
If you want to filter elements with exactly nil as a value, it is not correct, as Mr. Ilya wrote.
You can use detect this will return first value if match.
[:c, :b, :a].detect { |key| hash[key] != nill }. This will return :b.
Hope to help you :D

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.

Whether one of the elements of an array or a hash is nil

Is there any method that tells that one of the elements of an array or a hash is nil?
For an array
array = [1, 2, 'a']
array.any?(&:nil?)
#=> false
For a hash, I guess you are talking about nil values.
hash = {:a => 1, :b => 2, :c => nil}
hash.value?(nil)
#=> true
You can use the any? method: http://ruby-doc.org/core-1.9.3/Enumerable.html#method-i-any-3F
For example:arr.any? { |x| x.nil? }
As oldergod and strmstn have pointed out you should use any, and in the condition inside block you can verify whether an element is a nil or its class is Hash
[1,2,nil].any? {|x| x.class == Hash or x.nil? } # => true
[1,2,{}].any? {|x| x.class == Hash or x.nil? } # => true

Resources