Check if array contains more nils than other values

Check if array contains more nils than other values



Given an array with only odd counts:


[1,nil,nil]
[1,nil,Module,nil,2]
[1,Class.new,nil]



I would like to determine if there are nils or more non-nils. The approach I used was to make everything either true or false first. And then to determine if there are more true or false values:


[ 1,nil,nil,nil,2,3].collect val.max
#=> ArgumentError: comparison of TrueClass with false failed



The max method does not want to play nice with booleans. How can I accomplish this?



Now this might not be the best approach to determine whether there are more nils or non-nils, but this is the approach that I used.





Is it really the case that the array can only contain odd counts? Of course, for an even-length array, there could be an equal number of nil vs non-nil -- so how would you handle that? Your example of contains 0 elements; 0 is an even number.
– Tom Lord
Aug 30 at 18:29



nil


nil






I'm also unclear what the question is. The title says "true or false", your question says "truthy or false", then you say you want to count nil vs non-nil, then your code is using !!!val (which is surely just the same thing as !val?) - and is therefor actually counting the truthy vs falsey values.
– Tom Lord
Aug 30 at 18:33



!!!val


!val





What do you want the "result" of this method to be? true/false, depending on whether there are more truthy vs falsey values??
– Tom Lord
Aug 30 at 18:34


true


false





You've now been given 3 answers, all of which are wrong, because the original question was contradictory and confusing :(
– Tom Lord
Aug 30 at 19:56






Coming upon this question after several edits had been done I was perplexed why most of the answers were simply incorrect. That's what happens when you change the question after an answer has been posted. That earns a downvote from me. Incidentally, the best answer was given by @sagarpandya in a comment on Andrey's answer.
– Cary Swoveland
Aug 30 at 22:04





4 Answers
4



Given an array with only odd counts



If by that you mean that there will always be the nonequal amount of truthy/falsey values in an array, then, first of all, is not a valid input.




And here's the solution:


def truthy?(array)
falsey, truthy = array.partition(&:!)

truthy.size > falsey.size
end



You can go with oneliner if you prefer:


def truthy?(array)
array.partition(&:!).max_by(&:size).any?
end



Spec:


truthy?([1,nil,nil]) #=> false
truthy?([1,nil,nil,nil,2]) #=> false
truthy?([1,4,nil]) #=> true
truthy?([1,nil,nil]) #=> false
truthy?([1,nil,Module,nil,2]) #=> true
truthy?([1,Class.new,nil]) #=> true



It uses


Enumerable#partition


BasicObject#!



If you indeed intended to only calculate nils, not falsey values (as it was stated in the OP):


nil


def more_nils?(array)
array.partition(&:nil?).max_by(&:size).none?
end



Spec:


more_nils?([1,nil,nil]) #=> true
more_nils?([1,nil,nil,nil,2]) #=> true
more_nils?([1,4,nil]) #=> false
more_nils?([1,nil,nil]) #=> true
more_nils?([1,nil,Module,nil,2]) #=> false
more_nils?([1,Class.new,nil]) #=> false



It uses Object#nil? method.


Object#nil?



Inspired by @pjs's answer:


array.sum el.negative?



Even simpler ( from @SagarPandya's comment)


array.count(nil) > array.compact.count





The question was clarified -- apparently Donoto did want to count nil vs non-nil; I have no idea why they decided to convert everything to true/false first. Therefore this answer (while it does address the original ambiguous question) is not correct. You should be using element.nil? instead of !element.
– Tom Lord
Aug 30 at 19:55


nil


nil


true


false


element.nil?


!element





@TomLord added nil version
– Andrey Deineko
Aug 30 at 20:01


nil





That is a lot of work for arr.compact.size < arr.size / 2.0 or arr.compact.size / arr.size.to_f < 0.5
– engineersmnky
Aug 30 at 20:14



arr.compact.size < arr.size / 2.0


arr.compact.size / arr.size.to_f < 0.5





@engineersmnky I am not the one to call on "Ruby" way, but would you yourself approve code review if you saw arr.compact.size < arr.size / 2.0 introducing "magic number" (2), operating on initial input multiple times... Well, I don't say my second and third options are any better, but I bet that most Ruby devs would accept my very first option over both you presented :) (falsey, truthy = array.partition(&:nil?); falsey.size > truthy.size)
– Andrey Deineko
Aug 30 at 20:22



arr.compact.size < arr.size / 2.0


2


falsey, truthy = array.partition(&:nil?); falsey.size > truthy.size





arr.count(nil) > arr.compact.count
– Sagar Pandya
Aug 30 at 20:31


arr.count(nil) > arr.compact.count



A fairly straightforward solution would be:


def truthy?(ary)
ary.map bool.sum > 0
end



Map entries to +/-1 based on their truthiness, sum, and see whether the sum is positive or negative.



This can deal with empty arrays, it returns false in that case.


false





This is simpler and more efficient than the accepted answer. The accepted answer requires copying the whole array. It's easily adapted to check for nils.
– Schwern
Aug 30 at 20:42






could be simplified to sum with a block.
– Andrey Deineko
Aug 30 at 20:49



sum





@Schwern : The solution by pjs is elegant, but while it doesn't require copying of the array, it still creates a temporary object of the same size, so maybe using inject would be better (or sum, as has been suggested). Another problem is, that it produces wrong results if one of the array elements is false. I think we should use bool.nil? ? 1 : -1 inside the block.
– user1934428
Aug 31 at 6:07


inject


sum


false


bool.nil? ? 1 : -1





ary.map ... .sumary.sum ...
– Stefan
Aug 31 at 6:20



ary.map ... .sum


ary.sum ...



Here another one:


if array.size > 2*array.compact.size
# We have more nil than non-nil
end



Assuming that falsy values are nil and false, and everything else is truthy (as conditional statements do), you can leverage Object#itself with Array#select.


nil


false


Object#itself


Array#select


irb(main):013:0> ary = [1,nil,nil,false,2]
=> [1, nil, nil, false, 2]
irb(main):014:0> ary.select(&:itself).length
=> 2
irb(main):015:0> ary.reject(&:itself).length
=> 3



Required, but never shown



Required, but never shown






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

𛂒𛀶,𛀽𛀑𛂀𛃧𛂓𛀙𛃆𛃑𛃷𛂟𛁡𛀢𛀟𛁤𛂽𛁕𛁪𛂟𛂯,𛁞𛂧𛀴𛁄𛁠𛁼𛂿𛀤 𛂘,𛁺𛂾𛃭𛃭𛃵𛀺,𛂣𛃍𛂖𛃶 𛀸𛃀𛂖𛁶𛁏𛁚 𛂢𛂞 𛁰𛂆𛀔,𛁸𛀽𛁓𛃋𛂇𛃧𛀧𛃣𛂐𛃇,𛂂𛃻𛃲𛁬𛃞𛀧𛃃𛀅 𛂭𛁠𛁡𛃇𛀷𛃓𛁥,𛁙𛁘𛁞𛃸𛁸𛃣𛁜,𛂛,𛃿,𛁯𛂘𛂌𛃛𛁱𛃌𛂈𛂇 𛁊𛃲,𛀕𛃴𛀜 𛀶𛂆𛀶𛃟𛂉𛀣,𛂐𛁞𛁾 𛁷𛂑𛁳𛂯𛀬𛃅,𛃶𛁼

Edmonton

Crossroads (UK TV series)