Nov. 5th, 2009

rbandrews: (Lambda)
I had this idea in the shower today, and it works.

Let's say you have a big hash of key/value pairs, where the values are numbers and the keys are whatever. You want to divide them evenly into four or five smaller hashes with roughly equal sums of values.

My idea was to first divide them arbitrarily, then do 1000 iterations of moving a random element from the largest to the smallest piece.

And it works! Here's the (Ruby) code:

require "rubygems"
require "activesupport"

def partition values, count, tries = 1000
total = lambda{|s| s.values.sum }

largest = lambda{|s| s.max{|a,b| total[a] <=> total[b]} }

smallest = lambda{|s| s.min{|a,b| total[a] <=> total[b]} }

shift = lambda{|from, to|
key = from.keys.rand
to[key] = from.delete(key)
}

partitions = []
count.times{ partitions << {} }
values.keys.each_with_index{|key,i| partitions[i%count][key] = values[key] }

tries.times{ shift[ largest[partitions], smallest[partitions] ] }

partitions
end


Use it like this:

values = {}
(1..100).each{|n| values[n] = n }
partition(values, 5)


It'll yield 5 hashes, the sums of the values of each of which are 1010. Neat, huh?

Profile

rbandrews: (Default)
rbandrews

July 2024

S M T W T F S
 123456
78910111213
14151617181920
212223242526 27
28293031   

Style Credit

Page generated Jul. 8th, 2025 08:18 am
Powered by Dreamwidth Studios

Expand Cut Tags

No cut tags