2010-07-05 2 views
3

지역 및 도시 집합이 중첩되어 있고 알파벳순으로으로 주문 된 몇 개의 동일한 길이의 열로 출력 할 수 있기를 원합니다. 예를 들어 :레일에 짝수 간격으로 배열 된 주/보조 열

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

나는 'in_groups가'(그리고 'in_groups_of이') 그러나, 나는 (관계의 크기에 따라 그룹에 필요, 즉 도시의 수는 지역이 가지고 살펴했다). 이 작업을 수행하는 좋은 Rails 방법이 있는지 확실하지 않습니다. 지금까지 내 코드는 다음과 같습니다.

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

그러나 일부 지역은 극도로 균형이 맞지 않아 (올바르게 도시되지 않음) 올바르게 표시되지 않습니다.

답변

2

본인은 헬퍼 코드 여야하며보기에 포함되어서는 안된다는 데 동의합니다.

map = { 
    "Alberta" => ["Calgary", "Edmonton"], 
    "Manitoba" => ["Winnipeg"], 
    "Ontario" => ["Hamilton", "Kitchener", "Ottawa", "Toronto", "Waterloo"], 
    "Quebec" => ["Hull", "Laval", "Montreal"] 
} 

그것은 약 2 열을 생각하여 시작하는 것이 더 쉽습니다 :

는 해시에서 지방 간 도시지도를 가정하자. 2 열의 경우 첫 번째 열을 중단 할 위치를 결정하고 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 

그런 다음 우리는 여러 가지 방법을 모두 볼 수 있습니다 :

그래서 우리는 한 번에 여러 장소에서 목록을 분할 할 수 있도록의 함수를함으로써 시작하자

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을 직접 erate하십시오.따라서 모델과 뷰가 모두 변경 될 수 있지만 여전히이 코드를 재사용 할 수 있습니다. 이 함수는 자체 포함되어 있기 때문에 단위 테스트를 쉽게 작성할 수 있습니다. 4 개의 열의 균형을 유지해야하는 경우 find_best_columns 함수를 조정하거나 n 열을 지원하도록 재귀 적으로 다시 작성할 수 있습니다. 여기서 n은 다른 매개 변수입니다.

+0

감사합니다. Harold. 이것은 멋지다! –

1

왼쪽에서 오른쪽으로 알파벳 순으로 유지하려면 좋은 방법을 생각해 낼 수 없습니다. 네가 가진 것을 사용하라. 여기 내가 마음에 두었던 것에 대한 것이 있습니다. 이 도우미/컨트롤러/모델로 비트를 분할해야하지만 당신은 당신이 단지 필요가 HTML의 열을 줄 것

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 

을 생각하고 있었는지의 라인을 따라 뭔가 경우 당신에게 아이디어를 줄 것이다 당신의 시야에서 반복 할 수 있습니다.

+0

죄송합니다. 왼쪽에서 오른쪽 알파벳 순으로 정렬하려고했습니다. 또한이 코드는 열 높이의 균형을 유지하는 데 어떻게 도움이됩니까? –

+0

그냥 영역을 가져 와서 가장 낮은 높이의 열에 놓습니다. sort 명령은 가장 작은 크기의 열이 항상 0 위치가되도록 열을 다시 정렬합니다. 가장 큰 영역부터 가장 작은 영역까지 실행하면 상당히 균등하게 분배됩니다. –

+0

아, 이제 알겠습니다. 깔끔한 해결책이지만 알파벳면이 깨뜨리는 것은 옳습니다. –

관련 문제