One Array - 3 Columns of Equal Length

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! :slight_smile:

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 :slight_smile:

[...]

## 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. :slight_smile:

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

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

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,