File: active_support/core_ext/array/grouping.rb

Overview
Module Structure
Code

Overview

Module Structure

  module: <Toplevel Module>
  module: ActiveSupport#3
  module: CoreExtensions#4
  module: Array#5
  module: Grouping#6
has properties
method: in_groups_of / 2 #22
method: in_groups / 2 #59
method: split / 1 #90

Code

   1  require 'enumerator'
   2 
   3  module ActiveSupport #:nodoc:
   4    module CoreExtensions #:nodoc:
   5      module Array #:nodoc:
   6        module Grouping
   7          # Splits or iterates over the array in groups of size +number+,
   8          # padding any remaining slots with +fill_with+ unless it is +false+.
   9          # 
  10          #   %w(1 2 3 4 5 6 7).in_groups_of(3) {|group| p group}
  11          #   ["1", "2", "3"]
  12          #   ["4", "5", "6"]
  13          #   ["7", nil, nil]
  14          #
  15          #   %w(1 2 3).in_groups_of(2, '&nbsp;') {|group| p group}
  16          #   ["1", "2"]
  17          #   ["3", "&nbsp;"]
  18          #
  19          #   %w(1 2 3).in_groups_of(2, false) {|group| p group}
  20          #   ["1", "2"]
  21          #   ["3"]
  22          def in_groups_of(number, fill_with = nil)
  23            if fill_with == false
  24              collection = self
  25            else
  26              # size % number gives how many extra we have;
  27              # subtracting from number gives how many to add;
  28              # modulo number ensures we don't add group of just fill.
  29              padding = (number - size % number) % number
  30              collection = dup.concat([fill_with] * padding)
  31            end
  32 
  33            if block_given?
  34              collection.each_slice(number) { |slice| yield(slice) }
  35            else
  36              [].tap do |groups|
  37                collection.each_slice(number) { |group| groups << group }
  38              end
  39            end
  40          end
  41 
  42          # Splits or iterates over the array in +number+ of groups, padding any
  43          # remaining slots with +fill_with+ unless it is +false+.
  44          #
  45          #   %w(1 2 3 4 5 6 7 8 9 10).in_groups(3) {|group| p group}
  46          #   ["1", "2", "3", "4"]
  47          #   ["5", "6", "7", nil]
  48          #   ["8", "9", "10", nil]
  49          #
  50          #   %w(1 2 3 4 5 6 7).in_groups(3, '&nbsp;') {|group| p group}
  51          #   ["1", "2", "3"]
  52          #   ["4", "5", "&nbsp;"]
  53          #   ["6", "7", "&nbsp;"]
  54          #
  55          #   %w(1 2 3 4 5 6 7).in_groups(3, false) {|group| p group}
  56          #   ["1", "2", "3"]
  57          #   ["4", "5"]
  58          #   ["6", "7"]
  59          def in_groups(number, fill_with = nil)
  60            # size / number gives minor group size;
  61            # size % number gives how many objects need extra accomodation;
  62            # each group hold either division or division + 1 items.
  63            division = size / number
  64            modulo = size % number
  65 
  66            # create a new array avoiding dup
  67            groups = []
  68            start = 0
  69 
  70            number.times do |index|
  71              length = division + (modulo > 0 && modulo > index ? 1 : 0)
  72              padding = fill_with != false &&
  73                modulo > 0 && length == division ? 1 : 0
  74              groups << slice(start, length).concat([fill_with] * padding)
  75              start += length
  76            end
  77 
  78            if block_given?
  79              groups.each{|g| yield(g) }
  80            else
  81              groups
  82            end
  83          end
  84 
  85          # Divides the array into one or more subarrays based on a delimiting +value+
  86          # or the result of an optional block.
  87          #
  88          #   [1, 2, 3, 4, 5].split(3)                # => [[1, 2], [4, 5]]
  89          #   (1..10).to_a.split { |i| i % 3 == 0 }   # => [[1, 2], [4, 5], [7, 8], [10]]
  90          def split(value = nil)
  91            using_block = block_given?
  92 
  93            inject([[]]) do |results, element|
  94              if (using_block && yield(element)) || (value == element)
  95                results << []
  96              else
  97                results.last << element
  98              end
  99 
 100              results
 101            end
 102          end
 103        end
 104      end
 105    end
 106  end