Я согласен, что это должен быть вспомогательный код, а не встроенный в представление.
Предположим, у вас есть карта провинции в городе в хэше:
map = {
"Alberta" => ["Calgary", "Edmonton"],
"Manitoba" => ["Winnipeg"],
"Ontario" => ["Hamilton", "Kitchener", "Ottawa", "Toronto", "Waterloo"],
"Quebec" => ["Hull", "Laval", "Montreal"]
}
Начать прощедумая о 2 столбцах.Для 2 столбцов мы хотим решить, где остановиться 1-й столбец и начать 2-й.Есть 3 варианта для этих данных: между Альбертой и Манитобой, Манитобой и Онтарио и между Онтарио и Квебеком.
Итак, давайте начнем с создания функции, позволяющей разделить список в нескольких местах одновременно:
def split(items, indexes)
if indexes.size == 0
return [items]
else
index = indexes.shift
first = items.take(index)
indexes = indexes.map { |i| i - index }
rest = split(items.drop(index), indexes)
return rest.unshift(first)
end
end
Затем мы можем взглянуть на все разные способы, которыми мы можем сделать 2 столбца:
require 'pp' # Pretty print function: pp
provinces = map.keys.sort
1.upto(provinces.size - 1) do |i|
puts pp(split(provinces, [i]))
end
=>
[["Alberta"], ["Manitoba", "Ontario", "Quebec"]]
[["Alberta", "Manitoba"], ["Ontario", "Quebec"]]
[["Alberta", "Manitoba", "Ontario"], ["Quebec"]]
Или мы можем посмотреть на разные способы, которыми мы можем сделать 3 столбца:
1.upto(provinces.size - 2) do |i|
(i+1).upto(provinces.size - 1) do |j|
puts pp(split(provinces, [i, j]))
end
end
=>
[["Alberta"], ["Manitoba"], ["Ontario", "Quebec"]]
[["Alberta"], ["Manitoba", "Ontario"], ["Quebec"]]
[["Alberta", "Manitoba"], ["Ontario"], ["Quebec"]]
Как только вы сможете это сделать, вы можете найти расположение, в котором столбцы имеют наиболее равномерную высоту.Нам понадобится способ найти высоту столбца:
def column_height(map, provinces)
provinces.clone.reduce(0) do |sum,province|
sum + map[province].size
end
end
Затем вы можете использовать цикл до того, чтобы найти 3 столбца с минимальной разницей между самым высоким и самым коротким столбцами:
def find_best_columns(map)
provinces = map.keys.sort
best_columns = []
min_difference = -1
1.upto(provinces.size - 2) do |i|
(i+1).upto(provinces.size - 1) do |j|
columns = split(provinces, [i, j])
heights = columns.map {|col| column_height(map, col) }
difference = heights.max - heights.min
if min_difference == -1 or difference < min_difference
min_difference = difference
best_columns = columns
end
end
end
return best_columns
end
Это даст вам список для каждого столбца:
puts pp(find_best_columns(map))
=>
[["Alberta", "Manitoba"], ["Ontario"], ["Quebec"]]
Это здорово, потому что вы выясняете, какие провинции принадлежат каждому столбцу независимо от структуры модели, и это не так.не генерировать HTML напрямую.Таким образом, модели и представления могут меняться, но вы все равно можете использовать этот код.Поскольку эти функции автономны, для них также легко написать модульные тесты.Если вам нужно сбалансировать 4 столбца, вам просто нужно настроить функцию find_best_columns или вы можете переписать ее рекурсивно для поддержки n столбцов, где n - другой параметр.