Reputation: 665
I have a bunch of objects, lets call them Items
, each Item
has, among other things, a weight
and a publisher
. I want to sort them by weight
(decreasing), but, and here's the tricky bit, ensure that no Items
with the same publisher
appear twice (or more) in a row.
I was thinking about using a sort_by
loop and keeping track of the publisher indexes along the way (with a hash using the publishers as the keys and arrays of indexes as values), but I'm not sure if that's the best way to go about this or how to take care of that in practice if it is the best way. Any suggestions?
EX:
say all theses items were in an array called items
and ordered randomly. I would like to sort them so the weight=2 items appear first and the items with 'foo' as the publisher don't appear next to each other if possible (if there were no other publishers in that weight class then they would appear next to each other)
items = [(id: 1, name: "item1", publisher: "foo", weight: 2),
(id: 2, name: "item2", publisher: "foo", weight: 2),
(id: 3, name: "item3", publisher: "baz", weight: 1),
(id: 4, name: "item4", publisher: "bar", weight: 2)]
puts custom_sorting_method(items)
would return
[(id: 1, name: "item1", publisher: "foo", weight: 2),
(id: 4, name: "item4", publisher: "bar", weight: 2),
(id: 2, name: "item2", publisher: "foo", weight: 2),
(id: 3, name: "item3", publisher: "baz", weight: 1)]
Upvotes: 0
Views: 109
Reputation: 46
You could try grouping by weight and sort each grouped list by publisher, followed by alternatively taking the first and last element of each sorted list. Very roughly:
results = []
alt_methods = [:shift, :pop]
grouped = items.group_by{ |item| item[:weight] }
grouped_and_sorted = grouped.each do |k,v|
v.sort_by { |item| item[:publisher] }
end
grouped_and_sorted.each do |k,v|
v.length.times{ |i| results << v.send(alt_methods[i%2]) }
end
Upvotes: 2
Reputation: 15945
# Sorts by weight, and then distributes by publisher within each weight.
#
# @param [Array<Hash>] items
# @return [Array<Hash>]
def special_sort(items)
by_weight_nested = Hash[
items
.group_by { |item| item[:weight] }
.map { |weight, arr| [weight, arr.group_by { |item| item[:publisher] }] }
]
sorted = []
by_weight_nested.keys.sort.reverse.each do |weight|
publishers = by_weight_nested[weight].keys
0.upto(by_weight_nested[weight].values.map(&:size).max - 1) do |i|
publishers.each do |publisher|
sorted << by_weight_nested[weight][publisher][i]
end
end
end
sorted.compact
end
Upvotes: 1
Reputation: 51
sorted = Items.sort{|x,y| y.weight <=> x.weight}
sorted.uniq!{|x| x.publisher}
Upvotes: 1