Project

General

Profile

Feature #12059

`Array#single?`, `Hash#single?`

Added by sawa (Tsuyoshi Sawada) over 3 years ago. Updated over 3 years ago.

Status:
Open
Priority:
Normal
Assignee:
-
Target version:
-
[ruby-core:73748]

Description

There are some use cases when one wants to check if an array or a hash has exactly one element. I propose Array#single? and Hash#single? that checks for such cases and returns either true or false. This is an analogy from the empty? method on the respective class.

  • When creating an inflectional form out of an array:
a = ["object1", "object2"]
"There #{a.single ? "is" : "are"} #{a.length} #{a.single? ? "object" : "objects"}."
# => "There are 2 objects."
  • When checking if all elements of the array are the same:
[1, 2, 2, 1].uniq.single? # => false
[1, 1, 1, 1].uniq.single? # => true

History

Updated by sikachu (Prem Sichanugrist) over 3 years ago

I feel like the usage of this method wouldn't be generic enough, and could be accomplished easily by .size.one?

Updated by mame (Yusuke Endoh) over 3 years ago

I'm neutral for the proposal itself. If it is accepted, I think "singleton?" is the best name.

In mathematics, a singleton ... is a set with exactly one element.

https://en.wikipedia.org/wiki/Singleton_(mathematics)

--
Yusuke Endoh mame@ruby-lang.org

Updated by danielpclark (Daniel P. Clark) over 3 years ago

Ruby currently supports the one? method on both Hash and Array.

[1].one?
# => true 
{a: 1}.one?
# => true 
[1].method(:one?).owner
# => Enumerable 

Updated by nobu (Nobuyoshi Nakada) over 3 years ago

[1, false, nil].one? also returns true.

From ri Enumerable#one?:


enum.one? [{ |obj| block }]   -> true or false

Passes each element of the collection to the given block. The method returns
true if the block returns true exactly once. If the block is not given, one?
will return true only if exactly one of the collection members is true.

%w{ant bear cat}.one? { |word| word.length == 4 }  #=> true
%w{ant bear cat}.one? { |word| word.length > 4 }   #=> false
%w{ant bear cat}.one? { |word| word.length < 4 }   #=> false
[ nil, true, 99 ].one?                             #=> false
[ nil, true, false ].one?                          #=> true

Updated by danielpclark (Daniel P. Clark) over 3 years ago

Right. Given the original examples by the OP Enumerable#one? works.

a = ["object1", "object2"]
"There #{a.one? ? "is" : "are"} #{a.length} #{a.one? ? "object" : "objects"}."
# => "There are 2 objects."
[1, 2, 2, 1].uniq.one?
# => false
[1, 1, 1, 1].uniq.one?
# => true

Also available in: Atom PDF