Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using a Ruby map on a range

Tags:

ruby

I'm trying to use .map so I don't need to initialize a products array.

Here's the original code:

products = []
for page in (1..(ShopifyAPI::Product.count.to_f/150.0).ceil)
  products += ShopifyAPI::Product.find(:all, :params => {:page => page, :limit => 150})
end

Here's what I've tried:

products = (1..(ShopifyAPI::Product.count.to_f/150.0).ceil).map do |page|
  ShopifyAPI::Product.find(:all, :params => {:page => page.to_i, :limit => 150})
end

Which only returns the first product? What am I doing wrong?

The ShopifyAPI::Product returns a list of products based on the sent parameters page, and limit.

like image 686
ByteMe Avatar asked Aug 11 '17 22:08

ByteMe


1 Answers

I'm not sure why you're finding the second snippet only returns the first product, but in order to make it functionally equivalent to the first, you could use flat_map instead of map here, or alternatively tack on a .flatten at the end (or flatten(1), if you want to be more specific)

Given that the .find call returns an array, you can see the difference in the following examples:

a = []
(0..2).each { |x| a += [x] }
# a == [0,1,2]

(0..2).map { |x| [x] }
# [[0], [1], [2]]

(0..2).flat_map { |x| [x] }
# [0, 1, 2]

That's because array + array combines the two of them.

If your first snippet instead used products.push(<find result>) then you'd see the same nested array result.

See Enumerable#flat_map and Array#flatten

like image 148
max pleaner Avatar answered Oct 02 '22 08:10

max pleaner