42

Select makes sense. But can someone explain .detect to me? I don't understand these data.

>> [1,2,3,4,5,6,7].detect { |x| x.between?(3,4) }
=> 3
>> [1,2,3,4,5,6,7].detect { |x| x.between?(3,6) }
=> 3
>> [1,2,3,4,5,6,7].detect { |x| x.between?(3,7) }
=> 3
>> [1,2,3,4,5,6,7].detect { |x| x.between?(2,7) }
=> 2
>> [1,2,3,4,5,6,7].detect { |x| x.between?(1,7) }
=> 1
>> [1,2,3,4,5,6,7].detect { |x| x.between?(6,7) }
=> 6
>> [1,2,3,4,5,6,7].select { |x| x.between?(6,7) }
=> [6, 7]
>> [1,2,3,4,5,6,7].select { |x| x.between?(1,7) }
=> [1, 2, 3, 4, 5, 6, 7]
JZ.
  • 21,147
  • 32
  • 115
  • 192

4 Answers4

86

Detect returns the first item in the list for which the block returns TRUE. Your first example:

>> [1,2,3,4,5,6,7].detect { |x| x.between?(3,4) }
=> 3

Returns 3 because that is the first item in the list that returns TRUE for the expression x.between?(3,4).

detect stops iterating after the condition returns true for the first time. select will iterate until the end of the input list is reached and returns all of the items where the block returned true.

ryeguy
  • 65,519
  • 58
  • 198
  • 260
  • 3
    Obligatory RubyDoc link: http://ruby-doc.org/core/classes/Enumerable.html#M003123 – Tom Morris Jun 07 '10 at 03:02
  • 27
    An alias for 'detect' is 'find'. For me it is easier to understand the semantics of the method if I think about it as 'find'. – Florin Oct 09 '12 at 08:36
  • 2
    Using "detect" and "find" interchangably does not appear to be correct however. If you check the ruby docs, if fact it points out in both the detect & find example code that they behave differently. It is in fact difficult to figure out the difference between "find" and "detect" because the explanatory text is ~exactly~ the same for both methods, but the explanatory methods differ. http://ruby-doc.org/core-2.2.1/Enumerable.html#method-i-find – Paul Dacus Apr 08 '15 at 13:40
  • 2
    @PaulDacus However when you expend the source code, #detect points to enum_find(...). So I assume #detect is an alias for #find here. – msg7086 May 16 '15 at 04:33
  • 5
    @PaulDacus The explanatory methods from `detect` and `find` in RubyDocs behave differently because they're being called by different objects: `(1..10)` vs `(1..100)`. – anthonygiuliano Jul 28 '16 at 13:21
  • There's also a missconception in the docs. The docs say `first for which block is not false`, which implies that you may return that value or even `nil` for a method which requires boolean. Instead, if it accepts truthy/falsy values, it should say so. – Dragas Sep 29 '17 at 06:43
11

detect just returns the first value that satisfies the predicate, if any, nil otherwise. select returns all the values that satisfy the predicate. a.detect { p } is analogous to a.select { p }[0]

 irb(main):001:0> [1,2,3].detect { true }
 => 1
 irb(main):002:0> [1,2,3].detect { false }
 => nil
 irb(main):003:0> [1,2,3].detect { |x| x % 2 == 0 }
 => 2
Logan Capaldo
  • 39,555
  • 5
  • 63
  • 78
5

The ruby-docs are a great ressource when you want to learn about the methods.

Enumerable#detect

Pran
  • 3,481
  • 2
  • 25
  • 27
4

find and detect will always either return a single object or they will return nil if nothing is matched:

[1,2,3,4,5,6,7].detect { |x| x.between?(1,7) }
=> 1

find_all and select will return an array of things that it finds that match:

[1,2,3,4,5,6,7].select { |x| x.between?(1,7) }
=> [1, 2, 3, 4, 5, 6, 7]

Reference Link

D Malan
  • 10,272
  • 3
  • 25
  • 50
Jacs
  • 115
  • 1
  • 1
  • 9