Andrew Grimm
Andrew Grimm

Reputation: 81470

Take all items with enumerable#take

How can I Enumerable#take all the things?

arr = [1, 2, 3]
# Works
arr.take(1)
# Gives RangeError: float Inf out of range of integer
arr.take(Float::INFINITY)
# Gives RangeError: float Inf out of range of integer
arr.take(1.0/0.0)
# RangeError: bignum too big to convert into `long'
arr.take(1000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000)
# TypeError: no implicit conversion from nil to integer
arr.take(nil)

If it's not possible to take all items with Enumerable#take, then I'd have to have the convoluted code in display_results_allowing_all_objects rather than the simple code in display_results.

MAX_ROWS = 1

# Simple code: Only two lines long.    
def display_results(results)
  results_to_display = results.take(MAX_ROWS)
  puts results_to_display.map{|result| result.join("\t")}.join("\n")
end

results = [["Foo", 1], ["Bar", 2], ["Baz", 3]]

display_results(results)

NEW_MAX_ROWS = Float::INFINITY

# Convoluted mess: six lines long
def display_results_allowing_all_objects(results)
  results_to_display = if NEW_MAX_ROWS == Float::INFINITY
                         results
                       else
                         results_to_display = results.take(NEW_MAX_ROWS)
                       end
  puts results_to_display.map{|result| result.join("\t")}.join("\n")
end

display_results_allowing_all_objects(results)

Upvotes: 2

Views: 263

Answers (4)

Muskworker
Muskworker

Reputation: 91

If you need to handle MAX_ROWS being any number up to and including Float::Infinity, you can do the check explicitly with take_while plus with_index:

results_to_display = results.take_while.with_index {|_result, index| index < MAX_ROWS }

Upvotes: 0

Nakilon
Nakilon

Reputation: 35064

We can do the [0..-1]. But with .. you can't get 0 items while with ... you can't get all of them. If you can deal with inability to get 0 results, use .., but you'll have to do -1, so the 0 will mean the all results:

results_to_display = results[0 .. rows_to_take-1]

Upvotes: 1

Rafa Paez
Rafa Paez

Reputation: 4860

You can use Enumerable#take_while to take all the items

$> arr.take_while { true }
 # => [1, 2, 3]

Upvotes: 1

Aaron Cronin
Aaron Cronin

Reputation: 2103

You could cast #to_a which would take everything:

arr = [1, 2, 3]
arr.to_a
#=> [1, 2, 3]

(1..4).lazy.to_a
#=> [1, 2, 3, 4]

Upvotes: -1

Related Questions