Count truthy objects in an array - ruby

I'd like to count truthy objects in an array. Since I can pass a block to count, the most idiomatic way I found was this:
[1, nil, 'foo', false, true].count { |i| i }
#=> 3
But I was wondering if there was a better way, especially using the syntax count(&:something), because passing a full block here looks like overkill to me.
AFAIK, there is no truthy? method in Ruby, so I couldn't find how to achieve this.

With Ruby >= 2.2 you can use Object#itself:
[1, nil, 'foo', false, true].count(&:itself)
#=> 3

Try this:
[1, nil, 'foo', false, true].count(true)

Related

Access `self` of an object through the parameters

Let's say I want to access an element of an array at a random index this way:
[1, 2, 3, 4].at(rand(4))
Is there a way to pass the size of the array like the following?
[1, 2, 3, 4].at(rand(le_object.self.size))
Why would I do that?--A great man once said:
Science isn't about why, it is about why not.
Not recommended, but instance_eval would somehow work:
[1, 2, 3, 4].instance_eval { at(rand(size)) }
And you can also break out of tap:
[1, 2, 3, 4].tap { |a| break a.at(rand(a.size)) }
There's an open feature request to add a method that yields self and returns the block's result. If that makes it into Ruby, you could write:
[1, 2, 3, 4].insert_method_name_here { |a| a.at(rand(a.size)) }
No, you can't do that. Receiver of a method (that array) is not accessible by some special name at the call site. Your best bet is assigning a name to that object.
ary = [1, 2, 3, 4]
ary.at(rand(ary.size))
Of course, if all you need is a random element, then .sample should be used. Which does not require evaluation of any arguments at the call site and its self is the array.
You can use instance_eval to execute ruby code with the binding of the array variable
[1, 2, 3, 4].instance_eval { at(rand(size)) }
Assuming you are interested in a random element as Array#at returns an element at given index, you can use Array#sample to pick a random element from an array.
[1,2,3,4].sample
#=> 3
If you do not want to use instance_eval (or any form of eval), then, you can add a method to Array class by monkey patching - generally speaking, I am not sure whether it's a wise idea to monkey patch though
class Array
def random_index
rand(size)
end
end
["a","b","c","d"].random_index
#=> 2
You could do something similar with lambda:
getrand = ->(x) { x[rand(x.count)] }
getrand.call [1,2,3]
# => 2

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.

Ruby remove nil values from array with .reject

I have an array:
scores = [1, 2, 3, "", 4]
And I want to remove all blank values. But when I run this:
puts scores.reject(&:empty?)
I get an error:
undefined method `empty' for 1:Fixnum
How can I remove values that are not integers from my array in a one step process? I am using Ruby 1.9.3.
To reject only nil would be:
array.compact
If you want to remove blank values, you should use blank?: (requires Rails / ActiveSupport)
scores.reject(&:blank?)
#=> [1, 2, 3, 4]
"", " ", false, nil, [], and {} are blank.
It is as simple as:
scores.grep(Integer)
Note that if you plan to map the values, you can do that in a block after:
scores.grep(Integer){|x| x+1 }
Bonus if you want to do the same thing, but your numbers are strings:
scores.grep(/\d+/){|x|x.to_i}
Try this :
scores.select{|e| e.is_a? Integer}
# => [1, 2, 3, 4]
If you really need reject nil only, so it can be done like this:
scores.reject(&:nil?)
scores = [1, 2, 3, "", 4, nil]
scores.reject{|s| s.to_s == ''}
# => [1, 2, 3, 4]
This Worked for me
scores.reject!{|x| x.to_s.empty?}
scores.select{|score| score.is_a? Fixnum}
or, as Fixnum inherits from Integer, you can also go for
scores.select{|score| score.is_a? Integer)
...if that seems more descriptive.
Array and Enumerable tend to offer many ways of doing the same thing.
&:empty? will work for hashes, arrays, and strings, but not numbers. The method you use in reject must be valid for all items in a list. &:blank? will work fine for this reason.

Can i check if an array e.g. just holds integers in ruby?

Title, i think is self declaring. I am kind of a java-developer and wanna ensure that my array holds just integer values. I know everything in ruby is a object. I find it inconvenient to loop through the array and make checks at every element. Is there any shortcut to this in ruby?
Use Enumerable#all? with a block. Integer numbers are instances of class Integer in ruby.
[1, 2, 3].all? {|i| i.is_a?(Integer) } # => true
[1, 2, 3, '4'].all? {|i| i.is_a?(Integer) } # => false

Clearing Empty Strings from an Array

I'm dealing with a bunch of arrays made of strings and many a times I've written .delete_if { |str| str.empty? }
Now, I know I can add this method to the array class myself but I'm hoping there's a built in way to do this without having non-standard methods added to base classes. As much fun as adding methods to base classes is, it's not something I wanna do for maintainability reasons.
Is there a built in method to handle this?
There is a short form
array.delete_if(&:empty?)
You can use this method:
1.9.3p194 :001 > ["", "A", "B", "C", ""].reject(&:empty?)
=> `["A", "B", "C"]`
Please note that you can use the compact method if you only got to clear an array from nils.
Well, there is Array.delete. It returns what's deleted (or nil if nothing is deleted) however, which feels clumsy. But it does deliver and does not fail on non-string elements:
ar = ['a', '', 2, 3, '']
p ar.delete('') #=> ""
p ar #=> ["a", 2, 3]
You can do this
ar = ['a', '', 2, 3, '']
ar = ar.select{|a| a != ""}
I hope this will work for you
You can use .select! but you're still going to run into the same problem.
Instead of modifying array, you could create a utility class instead.
You can try below solution. I hope it ll help you.
array = ["","",nil,nil,2,3]
array.delete_if(&:blank?) => [2,3]
If you also want to remove nil:
arr = ['',"",nil,323]
arr.map!{|x|x==''?nil:x}.compact!
=> [323]
Map, ternary operator, compact
For simple work around:
my_array = ['a', '', 2, 3, '']
compact_array = my_array.select(&:present?)
# => ["a", 2, 3]
Here:
We select only item of array that ruby think it's present while
nil and "" is not present? in ruby
As of Rails 5.2, Enumerable now supports .compact_blank, which does precisely what you're asking for:
[1, "", nil, 2, " ", [], {}, false, true, 3].compact_blank
# => [1, 2, true, 3]
It works on hashes as well, removing pairs that have a blank value.
Docs: https://apidock.com/rails/Enumerable/compact_blank

Resources