I want to split a single array into 3 columns of equal (or as near to as possible) length. What would you advise I do?
enjoy!
http://weblog.rubyonrails.org/2006/3/1/new-in-rails-enumerable-group_by-and-array-in_groups_of
enjoy!
This isn’t quite the same thing though.
a = %w(1 2 3 4 5 6 7 8 9 10)
a.in_groups_of(3)
=> [[“1”, “2”, “3”], [“4”, “5”, “6”], [“7”, “8”, “9”], [“10”, nil, nil]]
It gives you 4 groups, not three as the OP’s expecting.
I would use the Array#chunk method at http://blog.jayfields.com/2007/09/ruby-arraychunk.html like this:
a.chunk(3)
=> [[“1”, “4”, “7”, “10”], [“2”, “5”, “8”], [“3”, “6”, “9”]]
Cheers,
Andy
chewmanfoo wrote:
Ruby on Rails — New in Rails: Enumerable#group_by and Array#in_groups_of
enjoy!
Thank you for your quick response. Sadly, I can't get this array method to do what I wish. See below:
<% Category.all.in_groups_of(3, false) do |sorted_categories| %> | <% for category in sorted_categories %> <%= link_to category.name, :action => 'list', :category => category %> <% end %> <% end %>
The above is the code I'm using.
It currently sorts my categories as below:
> Category1 Category2 Category3 | Category4 Category5 Category6 |
This is not what I want. What I want is:
I want to split a single array into 3 columns of equal (or as near to as possible) length. What would you advise I do?
Well, that depends on whether you want the elements to flow row-wise or column-wise.
require 'enumerator'
=> true
array = %w[ a b c d e f g h i j k l m n ]
=> ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n"]
## Row-wise is easy
array.each_slice(3) do |a,b,c|
puts [a,b,c]*' ' end a b c d e f g h i j k l m n => nil
## Column-wise is a bit more work
row_count = (array.length + (3-1))/3
=> 5
columns =
=>
array.each_slice(row_count) do |col|
columns << col columns[-1] << nil while columns[-1].length < row_count end => nil
columns.transpose.each do |a,b,c|
puts [a,b,c]*' ' end a f k b g l c h m d i n e j => [["a", "f", "k"], ["b", "g", "l"], ["c", "h", "m"], ["d", "i", "n"], ["e", "j", nil]]
Enjoy!
-Rob
Rob Biedenharn http://agileconsultingllc.com Rob@AgileConsultingLLC.com
rab@GaslightSoftware.com
That looks a little clunky to me... I'd rather use
(array.length / 3.0).ceil
No difference in the result though!
But the OP's request is a little vague as people have pointed out - Should the three groups be 'shuffled' (ie one of each of the first three elements in each column, and one of each of the next three, and so on...)? or is it the 1st, 2nd, and 3rd third of elements grouped together? is it three arrays of equal size for use in the controller? or three columns in a view that's needed? and if in the view, is it data that can be presented in an HTML table, or will it be CSS floated layout elements?
Hopefully though, there's been enough suggestions and pointers to the API docs for Enumerable for the OP to get a result
[...]
## Column-wise is a bit more work
> row_count = (array.length + (3-1))/3 => 5 > columns = =>
[...]
Why go to all that trouble? in_groups and zip. Done. No arithmetic.
Best,
in_groups and in_groups_of
part of rails api - hadn't spotted those before and would never have thought of looking for them. I often wonder how many other useful little goodies I may be missing. Always useful to keep an eye on this group.
thanks Marnen
The have a page through the API docs... it's all in there!
There's interesting stuff in both the Ruby [1] and Rails [2] APIs. You'll learn loads from looking through both resources' methods for String, Integer, Array, Enumerable; and in Rails, the ActionView::Helpers are great eye openers.
[1] http://ruby-doc.org/ - look at the "core api" link for your version [2] http://api.rubyonrails.org/
Marnen Laibow-Koser wrote:
[...]
## Column-wise is a bit more work
> row_count = (array.length + (3-1))/3 => 5 > columns = =>
[...]
Why go to all that trouble? in_groups and zip. Done. No arithmetic.
Best, -- Marnen Laibow-Koser http://www.marnen.org marnen@marnen.org
That really depends on what the desired output is. The OP indicated that he was looking for a phone book style sorting, top-to-bottom, left-to-right.
It currently sorts my categories as below:
> Category1 Category2 Category3 | Category4 Category5 Category6 |
This is not what I want. What I want is:
> Category1 | Category4 | > Category2 | Category5 | > Category3 | Category6 |
in_groups doesn't do exactly that. Here is an example:
Given a = [1,2,3,4,5,6,7,8,9] and I want the output to be
1 6 2 7 3 8 4 9 5
a = [1,2,3,4,5,6,7,8,9]
=> [1, 2, 3, 4, 5, 6, 7, 8, 9]
a.in_groups(2)
=> [[1, 2, 3, 4, 5], [6, 7, 8, 9, nil]]
a.in_groups_of(2)
=> [[1, 2], [3, 4], [5, 6], [7, 8], [9, nil]]
Here is a method that was constructed back in the Rails 1.2 days [1]:
def in_vertical_groups_of(number, fill_with = nil, &block) return in_groups_of((size.to_f / number).ceil, fill_with, &block).transpose end
a.in_vertical_groups_of(2)
=> [[1, 6], [2, 7], [3, 8], [4, 9], [5, nil]]
I add this to something that is in config/intializers
module ActiveSupport module CoreExtensions module Array module Grouping def in_vertical_groups_of end end end end end
Peace, Phillip
[1] original thread: In_vertical_groups_of - Rails - Ruby-Forum
Phillip Koebbe wrote:
Marnen Laibow-Koser wrote:
[...]
## Column-wise is a bit more work
> row_count = (array.length + (3-1))/3 => 5 > columns = =>
[...]
Why go to all that trouble? in_groups and zip. Done. No arithmetic.
Best, -- Marnen Laibow-Koser http://www.marnen.org marnen@marnen.org
That really depends on what the desired output is.
You're right. I assumed the OP wanted the output he said he wanted.
The OP indicated that he was looking for a phone book style sorting, top-to-bottom, left-to-right.
I know that.
It currently sorts my categories as below:
> Category1 Category2 Category3 | Category4 Category5 Category6 |
This is not what I want. What I want is:
> Category1 | Category4 | > Category2 | Category5 | > Category3 | Category6 |
in_groups doesn't do exactly that.
I'm aware of that. That's why I suggested in_groups *and zip*, which will do exactly what the OP wanted.
Please don't only read half of my solution and claim I'm wrong because you missed the rest.
Best,
Marnen Laibow-Koser wrote:
Phillip Koebbe wrote:
Marnen Laibow-Koser wrote:
[...]
## Column-wise is a bit more work
> row_count = (array.length + (3-1))/3 => 5 > columns = =>
[...]
Why go to all that trouble? in_groups and zip. Done. No arithmetic.
Best, -- Marnen Laibow-Koser http://www.marnen.org marnen@marnen.org
I'm aware of that. That's why I suggested in_groups *and zip*, which will do exactly what the OP wanted.
Please don't only read half of my solution and claim I'm wrong because you missed the rest.
I didn't realize "zip" was a reference to a method call. I actually thought you were making a reference to something speedy. You know, like "Zip, you're done." Since "zip" was followed by "Done", who was I to question your placement of a period. For that oversight, I'm terribly sorry.
Relax.
Peace, Phillip
Phillip Koebbe wrote:
Marnen Laibow-Koser wrote:
[...]
## Column-wise is a bit more work
> row_count = (array.length + (3-1))/3 => 5 > columns = =>
[...]
Why go to all that trouble? in_groups and zip. Done. No arithmetic.
Best, -- Marnen Laibow-Koser http://www.marnen.org marnen@marnen.org
That really depends on what the desired output is.
You're right. I assumed the OP wanted the output he said he wanted.
The OP indicated that he was looking for a phone book style sorting, top-to-bottom, left-to-right.
I know that.
It currently sorts my categories as below:
> Category1 Category2 Category3 | Category4 Category5 Category6 |
This is not what I want. What I want is:
> Category1 | Category4 | > Category2 | Category5 | > Category3 | Category6 |
in_groups doesn't do exactly that.
I'm aware of that. That's why I suggested in_groups *and zip*, which will do exactly what the OP wanted.
Please don't only read half of my solution and claim I'm wrong because you missed the rest.
It would be so much less confusing if you would answer in actual *code* rather than just spewing documentation.
-Rob
Best, -- Marnen Laibow-Koser http://www.marnen.org marnen@marnen.org
Sent from my iPhone -- Posted via http://www.ruby-forum.com/.
-- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk@googlegroups.com. To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe@googlegroups.com. For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.
Rob Biedenharn Rob@AgileConsultingLLC.com http://AgileConsultingLLC.com/ rab@GaslightSoftware.com http://GaslightSoftware.com/
Phillip Koebbe wrote: [...]
I didn't realize "zip" was a reference to a method call. I actually thought you were making a reference to something speedy. You know, like "Zip, you're done." Since "zip" was followed by "Done", who was I to question your placement of a period. For that oversight, I'm terribly sorry.
Oh, now I understand the confusion. Yeah, that would do it.
Relax.
Peace, Phillip
Best,
Rob Biedenharn wrote:
It currently sorts my categories as below:
I'm aware of that. That's why I suggested in_groups *and zip*, which will do exactly what the OP wanted.
Please don't only read half of my solution and claim I'm wrong because you missed the rest.
It would be so much less confusing if you would answer in actual *code* rather than just spewing documentation.
I told the OP which methods would do the job for him. I didn't "spew documentation" as I understand that phrase. I didn't write code, either, because I generally don't like to do that for others on the list (as I do not expect others to do it for me), unless the solution is fairly complex and/or unintuitive. In this case, I don't really think it was.
-Rob
Best,
Your response was quoting a bit of code to which you said "Why go to all that trouble?" and then mentioned two methods. I think it would have been better to demonstrate how those two methods would avoid the "trouble" than to have simply tossed them out.
-Rob
Rob Biedenharn Rob@AgileConsultingLLC.com http://AgileConsultingLLC.com/ rab@GaslightSoftware.com http://GaslightSoftware.com/
Rob Biedenharn wrote:
Please don't only read half of my solution and claim I'm wrong
(as I do not expect others to do it for me), unless the solution is marnen@marnen.org
Your response was quoting a bit of code to which you said "Why go to all that trouble?" and then mentioned two methods. I think it would have been better to demonstrate how those two methods would avoid the "trouble" than to have simply tossed them out.
Again, I'm sorry if it was confusing. I think I was pressed for time when I responded, and anyhow, there are only a couple of ways one could combine the two methods, so I didn't think further explanation was necessary. Perhaps I misjudged it.
-Rob
Best,