From d9fee4517626c8d747b5e8aa7858f9ed77f9685e Mon Sep 17 00:00:00 2001 From: Adrian Mugnolo Date: Tue, 15 Jul 2008 01:17:03 -0300 Subject: [PATCH] Add in_groups to ActiveSupport::CoreExtensions::Array::Grouping --- .../lib/active_support/core_ext/array/grouping.rb | 47 ++++++++++++++++++- activesupport/test/core_ext/array_ext_test.rb | 50 ++++++++++++++++++-- 2 files changed, 91 insertions(+), 6 deletions(-) diff --git a/activesupport/lib/active_support/core_ext/array/grouping.rb b/activesupport/lib/active_support/core_ext/array/grouping.rb index 767acc4..a57619a 100644 --- a/activesupport/lib/active_support/core_ext/array/grouping.rb +++ b/activesupport/lib/active_support/core_ext/array/grouping.rb @@ -4,8 +4,8 @@ module ActiveSupport #:nodoc: module CoreExtensions #:nodoc: module Array #:nodoc: module Grouping - # Iterates over the array in groups of size +number+, padding any remaining - # slots with +fill_with+ unless it is +false+. + # Splits or iterates over the array in groups of size +number+, + # padding any remaining slots with +fill_with+ unless it is +false+. # # %w(1 2 3 4 5 6 7).in_groups_of(3) {|g| p g} # ["1", "2", "3"] @@ -39,6 +39,49 @@ module ActiveSupport #:nodoc: end end + # Splits or iterates over the array in +number+ of groups, padding any + # remaining slots with +fill_with+ unless it is +false+. + # + # %w(1 2 3 4 5 6 7 8 9 10).in_groups(3) {|g| p g} + # ["1", "2", "3", "4"] + # ["5", "6", "7", nil] + # ["8", "9", "10", nil] + # + # %w(1 2 3 4 5 6 7).in_groups(3, ' ') {|g| p g} + # ["1", "2", "3"] + # ["4", "5", " "] + # ["6", "7", " "] + # + # %w(1 2 3 4 5 6 7).in_groups(3, false) {|g| p g} + # ["1", "2", "3"] + # ["4", "5"] + # ["6", "7"] + def in_groups(number, fill_with = nil, &block) + # size / number gives minor group size; + # size % number gives how many objects need extra accomodation; + # each group hold either division or division + 1 items. + division = size / number + modulo = size % number + + # create a new array avoiding dup + groups = [] + start = 0 + + number.times do |index| + length = division + (modulo > 0 && modulo > index ? 1 : 0) + padding = fill_with != false && + modulo > 0 && length == division ? 1 : 0 + groups << slice(start, length).concat([fill_with] * padding) + start += length + end + + if block_given? + groups.each(&block) + else + groups + end + end + # Divides the array into one or more subarrays based on a delimiting +value+ # or the result of an optional block. # diff --git a/activesupport/test/core_ext/array_ext_test.rb b/activesupport/test/core_ext/array_ext_test.rb index 7563be4..62a1f61 100644 --- a/activesupport/test/core_ext/array_ext_test.rb +++ b/activesupport/test/core_ext/array_ext_test.rb @@ -99,7 +99,7 @@ class ArrayExtToSTests < Test::Unit::TestCase end class ArrayExtGroupingTests < Test::Unit::TestCase - def test_group_by_with_perfect_fit + def test_in_groups_of_with_perfect_fit groups = [] ('a'..'i').to_a.in_groups_of(3) do |group| groups << group @@ -109,7 +109,7 @@ class ArrayExtGroupingTests < Test::Unit::TestCase assert_equal [%w(a b c), %w(d e f), %w(g h i)], ('a'..'i').to_a.in_groups_of(3) end - def test_group_by_with_padding + def test_in_groups_of_with_padding groups = [] ('a'..'g').to_a.in_groups_of(3) do |group| groups << group @@ -118,7 +118,7 @@ class ArrayExtGroupingTests < Test::Unit::TestCase assert_equal [%w(a b c), %w(d e f), ['g', nil, nil]], groups end - def test_group_by_pads_with_specified_values + def test_in_groups_of_pads_with_specified_values groups = [] ('a'..'g').to_a.in_groups_of(3, 'foo') do |group| @@ -128,7 +128,7 @@ class ArrayExtGroupingTests < Test::Unit::TestCase assert_equal [%w(a b c), %w(d e f), ['g', 'foo', 'foo']], groups end - def test_group_without_padding + def test_in_groups_of_without_padding groups = [] ('a'..'g').to_a.in_groups_of(3, false) do |group| @@ -137,6 +137,48 @@ class ArrayExtGroupingTests < Test::Unit::TestCase assert_equal [%w(a b c), %w(d e f), ['g']], groups end + + def test_in_groups_returned_array_size + array = (1..7).to_a + + 1.upto(array.size + 1) do |number| + assert_equal number, array.in_groups(number).size + end + end + + def test_in_groups_with_empty_array + assert_equal [[], [], []], [].in_groups(3) + end + + def test_in_groups_with_block + array = (1..9).to_a + groups = [] + + array.in_groups(3) do |group| + groups << group + end + + assert_equal array.in_groups(3), groups + end + + def test_in_groups_with_perfect_fit + assert_equal [[1, 2, 3], [4, 5, 6], [7, 8, 9]], + (1..9).to_a.in_groups(3) + end + + def test_in_groups_with_padding + array = (1..7).to_a + + assert_equal [[1, 2, 3], [4, 5, nil], [6, 7, nil]], + array.in_groups(3) + assert_equal [[1, 2, 3], [4, 5, 'foo'], [6, 7, 'foo']], + array.in_groups(3, 'foo') + end + + def test_in_groups_without_padding + assert_equal [[1, 2, 3], [4, 5], [6, 7]], + (1..7).to_a.in_groups(3, false) + end end class ArraySplitTests < Test::Unit::TestCase -- 1.5.5.3