Even intermediate primary / secondary columns in rails

I have a set of regions and cities (nested) and I want to be able to display them in several columns with the same length, sorted in alphabetical order . For instance:

[Alberta]   [Ontario]   [Quebec]
Calgary     Hamilton    Hull
Edmonton    Kitchener   Laval
[Manitoba]  Ottawa      Montreal
Winnipeg    Toronto
            Waterloo

I looked at in_groups ' (and ' in_groups_of '), however I need to group based on the size of the relationship (i.e. the number of cities in the region). Not sure if there is a good Rails way to do this. So far, my code looks something like this:

<% regions.in_groups(3, false) do |group| %>
  <div class="column">
    <% group.each do |region| %>
      <h1><%= region.name %></h1>
      <% region.cities.each do |city| %>
        <p><%= city.name %></p>
      <% end %>
    <% end %>
  </div>
<% end %>

However, some regions are extremely unbalanced (i.e. they have many cities) and are not displayed correctly.

+3
source share
2 answers

, , .

, :

 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

, :

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 - .

+2

, . , . . // , , - , .

def region_columns(column_count)
  regions = Region.all(:include => :cities)
  regions.sort!{|a,b| a.cities.size <=> b.cities.size}.invert
  columns = Array.new(column_count, [])

  regions.each do |region|
    columns.sort!{|a,b| a.size <=> b.size}
    columns[0] << "<h1>#{region.name}</h1>"
    columns[0] << region.cities.map{|city| "<p>#{city.name}</p>"}
    columns[0].flatten
  end

  columns
end

html, .

+1

Source: https://habr.com/ru/post/1753105/


All Articles