So my question is the cleanest way to do #product_panels_for
below:
class ProductPanel < Struct.new(:product)
end
class ProductPresenter
def product_panels_for(selected_products)
selected_products.map do |product|
product_panels.find { |panel| panel.product.to_s == product }
end.
compact
end
def product_panels
[ProductPanel.new(:iphone), ProductPanel.new(:ipad), ProductPanel.new(:ibidet)]
end
end
ProductPresenter.new.product_panels_for(['ipad', 'iphone']) # => [<ProductPanel product=:ipad>, <ProductPanel product=:iphone>]
This is obviously simplified, but the point is #product_panels_for
should return values from product_panels
but in the order given in selected_panels
. Maybe this is fine is just feels a bit gangly for something that seems conceptually simpler than that.
To be clear the order is defined by the business, it won't be alphabetical or anything nice.
In case anyone's thinking it, yes, I know in Ruby 2.7 I could replace .map...compact
with .filter_map
, but I'm not on 2.7 yet.
My previous implementation was:
def product_panels_for(selected_products)
product_panels.select { |pp| selected_products.include?(pp) }
end
which was nice and clean but didn't preserve the order of selected_products.
If the implementation at the top can't be improved on, is there a nice way to use this previous implementation but chain something after the select that sorts the result so the order matches selected_products
? I'm just generally curious about a good way to cleanly sort A so its order matches B where B is a list of values for an attributes of A.
-
\$\begingroup\$ Did you notice that if you have duplicate products you only get one product panel? If you are assuming a 1-to-` relationship then that's probably fine... \$\endgroup\$Garrett Motzner– Garrett Motzner2020年04月03日 01:29:18 +00:00Commented Apr 3, 2020 at 1:29
1 Answer 1
Your solution looks good to me, I tried some alternatives but they end up being a little more verbose and not adding value that makes it worth.
Also, I don't think it is worth adding one more step to order it just to use select
.
I would go with your first solution.