2016-05-17 57 views
1

我有五個類別,每個類別有五個職位。例如。如何交錯多個ActiveRecord關聯查詢?

=> category_a.posts 
=> #<Post id:01>, #<Post id:02>, #<Post id:03> etc 

=> category_b.posts 
=> #<Post id:10>, #<Post id:11>, #<Post id:12> etc 

=> category_c.posts 
=> #<Post id:20>, #<Post id:21>, #<Post id:22> etc 

我想在那裏它們被交錯孩子的集合(儘可能均勻地),即

#<Post id:01>, #<Post id:10>, #<Post id:20>, #<Post id:02>, #<Post id:11> etc 

我怎麼能做到這一點?

回答

2

Dave Schweisguth的回答很好,可能會讓你知道你需要知道什麼來解決問題。但是,這種解決方案並不讓你選擇的項目將在交錯的順序這裏是一個有希望,更通用的解決方案。

def full_zip(*args) 
    max_len = args.map(&:length).max 
    ([nil] * max_len).zip(*args).flatten.compact 
end 

,然後本想full_zip(category_a.posts, category_b.posts, category_c.posts)full_zip(*[cat_a, cat_z].map(&:posts))使用。使用任何您想要它們的順序的類別。

編輯:這個問題的一個問題是如果原始列表中有你想保留的nils。

+0

我的解決方案的下一個演進將是用'nil'將所有數組填充到給定長度,然後放棄排序以保持順序,但這樣更好。小建議:'max_len' ='args.max_by&:length',只需使用'Array [max_len]'而不是'[nil] * max_len'。 –

+0

'Array [max_len]'的東西可能更符合語義,但我認爲它的'Array.new(max_len)'或'Array.new(max_len,nil)'。乘法技巧很好,因爲在製作新的陣列時(從舊的陣列,或者不需要使用平坦的花式形狀),它可能會更簡單一些。 – user2251284

+0

'max_by'技巧也不錯,但它必須是'foo.max_by(&:length).length'我認爲,因爲max只是返回元素。 – user2251284

1

它只有五個查詢和周圍15個型號,所以這將是細做它在內存中:

posts = 
    [category_a, category_b, category_c, category_d, category_e]. 
    map(&:posts) 
    sort_by(&:length) 
posts.first.zip(*posts[1..-1]).flatten.compact 

把最長的陣列第一防止zip來自於它的參數是長數組下降元素比它所調用的數組要多。 compact刪除由zip創建的任何nil,如果其參數中的數組長於所調用的數組。

+0

我的理解是,通過這種方式,zip會忽略類別b到e中的項目項目,它們的原始數組中的索引高於類別a中的最高索引,如果有意義的話。詳情請看這裏:http://apidock.com/ruby/Array/zip。 – user2251284

+0

另一件事,雖然我不確定,但是在這種情況下,category_a的帖子將與帖子列表交錯。這可以用「[1,1,1] .zip([[2,2,2],[3,3,3],[4,4,4]])」=> [[1,[ 2,2,2]],[1,[3,3,3]],[1,[4,4,4]]]。我認爲在發送給zip函數的數組之前有一個「*」符號會解構該數組並解決此問題。或者,我認爲你可以在「map(&:posts)」之後展平(我認爲你還需要額外的冒號)。 – user2251284

+0

由於編輯,我上面的兩個評論應該不再是問題。現在要考慮的一件事是,程序的用戶無法真正控制帖子現在壓縮的順序,而這僅取決於任何類別的帖子最多。如果你想維持nils,它也會遇到和我一樣的問題。如果這對任何人都很重要,請留下評論,我可以補充一點。 – user2251284