Reputation: 61
I'm looking to create a method that will return to me the 5 closest numbers in an array. Here is what I have to get me started. I'm looking to compare differences but I feel there has to be a simpler way .
def get_suggested_items
@suggested_items = []
new_price = self.price
products = Product.all
products.each do |product, difference|
price = product.price
old_difference = new_price - product.price
difference = (new_price - product.price).abs
while difference < old_difference
@suggested_items << product
end
end
I'm looking to have returned the array @suggested_items with the 5 closest products by the price
Upvotes: 0
Views: 2940
Reputation: 110675
Suppose arr
is a sorted array of integers. (If it's not sorted, then sort as the first step.)
I assume you want to find a sequence of five elements from the array, a = arr[i,5]
, such that a.last-a.first
is minimum for all i
, 0 <= i <= arr.size-4
. If that's correct, then it's simply:
start_index = (arr.size-4).times.min_by { |i| arr[i+4]-arr[i] }
Suppose
arr = [1, 2, 4, 5, 8, 9, 11, 12, 13, 15, 17, 19, 23, 24, 24, 25, 30]
start_index = (arr.size-4).times.min_by { |i| arr[i+4]-arr[i] }
#=> 4
So the "closest" five numbers would be:
arr[4,5]
#=> [8, 9, 11, 12, 13]
Upvotes: 1
Reputation: 1995
SQL was designed for this sort of thing. Add the following class method to your Product
model:
class Product < ActiveRecord::Base
def self.with_price_nearest_to(price)
order("abs(products.price - #{price})")
end
end
Then you can write:
Product.with_price_nearest_to(3.99).limit(5)
There is a distinct performance advantage to this approach over what you outlined in your question. In this case, the database does the calculation and sorting for you and returns to ActiveRecord only the 5 products that you need. When you do Product.all
or even Product.each
you're forcing ActiveRecord to instantiate a model for every row in your table, which gets expensive as the table gets larger.
Note that this approach still requires a full table scan; if you want to improve the performance further, you can add an index to price
column on the products
table.
Upvotes: 4