Ruby 跨多个列进行排序和平衡 问题
我有一个看起来像这样的散列数据Ruby 跨多个列进行排序和平衡 问题,ruby,algorithm,optimization,knapsack-problem,Ruby,Algorithm,Optimization,Knapsack Problem,我有一个看起来像这样的散列数据 { "GROUP_A" => [22, 440], "GROUP_B" => [14, 70], "GROUP_C" => [60, 620], "GROUP_D" => [174, 40], "GROUP_E" => [4, 12] # ...few hundred more } A组有22个帐户,他们使用440GB的数据…等等。有几百个这样的团体。有些人有很多账户,但使用很少的存储空间;有些人只有几个用户,但使用了很多存储空间;
{ "GROUP_A" => [22, 440],
"GROUP_B" => [14, 70],
"GROUP_C" => [60, 620],
"GROUP_D" => [174, 40],
"GROUP_E" => [4, 12]
# ...few hundred more
}
A组有22个帐户,他们使用440GB的数据…等等。有几百个这样的团体。有些人有很多账户,但使用很少的存储空间;有些人只有几个用户,但使用了很多存储空间;有些人只是普通人
我有X个存储桶(服务器),我希望将这些帐户组放入其中,我希望每个存储桶的帐户数量大致相同,并且每个存储桶也包含大致相同的数据量。组的数量并不重要,因此,如果一个存储桶中有1组1000个帐户使用500GB的数据,而下一个存储桶中有10组97个帐户(总共970个)使用450GB的数据,我认为这是好的
到目前为止,我还没有想出一个算法来做到这一点。在我的脑海里我在想这样的事情也许
PASS 1
Bucket 1: Group with largest data, 60 users.
Bucket 2: Next largest data group, 37 users.
Bucket 3: Next largest data group, 72 users.
Bucket 4: etc....
PASS 2
Bucket 1: Add a group with small amount of data, but more users than average.
# There's probably a ratio I can calculate to figure this out...divide users/datavmaybe?
Bucket 2: Find a "small data" group where sum of users in Bucket 1 ~= sum of users in Bucket 2
# But then there's no guarantee that the data usages will be close enough
Bucket 3: etc...
PASS 3
Bucket 1: Now what? Back to next largest data group?
我仍然认为有更好的方法来解决这个问题,但我没有想到。如果有人有任何想法,我愿意接受建议
马特
解决方案1.1-暴力更新
嗯……这是第一次尝试的更新。这仍然不是一个“背包问题”的解决方案。只需强制执行数据,使帐户在各个存储桶之间保持平衡。这一次,我添加了一些逻辑,这样,如果一个bucket的完整帐户百分比高于数据百分比,它将根据帐户数量找到最适合的最大组(按数据)。与第一次尝试相比,我现在获得了更好的数据分布(如果您想查看第一次尝试,请参阅编辑历史记录)
现在我按顺序装每个桶,先装一桶,然后装二桶,等等。。。我想,如果我修改代码以便同时(或几乎同时)填充它们,我会获得更好的数据平衡
e、 g.第一个部门进入桶1,第二个部门进入桶2,以此类推…直到所有桶都有一个部门。。。然后再次从铲斗1开始
dept_arr_sorted_by_acct = dept_hsh.sort_by {|key, value| value[0]}
ap "MAX ACCTS: #{max_accts} AVG ACCTS: #{avg_accts}"
ap "MAX SIZE: #{max_size} AVG SIZE: #{avg_data}"
# puts dept_arr_sorted_by_acct
# exit
bucket_arr = Array.new
used_hsh = Hash.new
server_names.each do |s|
bucket_hsh = Hash.new
this_accts=0
this_data=0
my_key=""
my_val=[]
accts=0
data=0
accts_space_pct_used = 0
data_space_pct_used = 0
while this_accts < avg_accts
if accts_space_pct_used <= data_space_pct_used
# This loop runs if the % used of accts is less than % used of data
dept_arr_sorted_by_acct.each do |val|
# Sorted by num accts - ascending. Loop until we find the last entry in the array that has <= accts than what we need
next if used_hsh.has_key?(val[0])
#do nothing
if val[1][0] <= avg_accts-this_accts
my_key = val[0]
my_val = val[1]
accts = val[1][0]
data = val[1][1]
end
end
else
# This loop runs if the % used of data is less than % used of accts
dept_arr_sorted_by_data = dept_arr_sorted_by_acct.sort { |a,b| b[1][1] <=> a[1][1] }
dept_arr_sorted_by_data.each do |val|
# Sorted by size - descending. Find the first (largest data) entry where accts <= what we need
next if used_hsh.has_key?(val[0])
# do nothing
if val[1][0] <= avg_accts-this_accts
my_key = val[0]
my_val = val[1]
accts = val[1][0]
data = val[1][1]
break
end
end
end
used_hsh[my_key] = my_val
bucket_hsh[my_key] = my_val
this_accts = this_accts + accts
this_data = this_data + data
accts_space_pct_used = this_accts.to_f / avg_accts * 100
data_space_pct_used = this_data.to_f / avg_data * 100
end
bucket_arr << [this_accts, this_data, bucket_hsh]
end
x=0
while x < bucket_arr.size do
th = bucket_arr[x][2]
list_of_depts = []
th.each_key do |key|
list_of_depts << key
end
ap "Bucket #{x}: #{bucket_arr[x][0]} accounts :: #{bucket_arr[x][1]} data :: #{list_of_depts.size} departments"
#ap list_of_depts
x = x+1
end
(379*62279)我仍然需要弄清楚,当MAX_账户不能被桶数平均整除时,如何解释。我试着在平均账户值上加上1%的pad,这意味着平均值应该是383,但所有的存储桶都说它们有383个账户……这不可能是真的,因为存储桶中的账户比最大账户多。我在代码中的某个地方发现了一个尚未发现的错误。这是一个示例。有一些解决方案,但这是一个非常棘手的问题,研究一个好的解决方案比尝试自己的解决方案要好。啊……这很有趣,谢谢链接。我可以通过将总账户和总数据除以我想放入的存储桶数来计算我的最大限额。。。。而且可能会使第一个桶在两个值上都接近最大值……但我想在最后几个桶上会越来越难。是的,这是你的情况存在的一个困难,而不是最初问题的一部分。我相信您将能够将本文中的技术应用于多背包问题。甚至可能会有一个章节专门讨论这个问题。可能更糟:这里有一个问题
"MAX ACCTS: 2279 AVG ACCTS: 379"
"MAX SIZE: 1693315 AVG SIZE: 282219"
"Bucket 0: 379 accounts :: 251670 data :: 7 departments"
"Bucket 1: 379 accounts :: 286747 data :: 10 departments"
"Bucket 2: 379 accounts :: 278226 data :: 14 departments"
"Bucket 3: 379 accounts :: 281292 data :: 19 departments"
"Bucket 4: 379 accounts :: 293777 data :: 28 departments"
"Bucket 5: 379 accounts :: 298675 data :: 78 departments"