class Garoupa

Constants

DEFAULT_GROUP_SIZE
VERSION

Attributes

groups[R]
list[R]
past_groupmates[R]

Public Class Methods

make_groups(list, options = {}) click to toggle source
# File lib/garoupa.rb, line 8
def self.make_groups(list, options = {})
  list_items_past_groupmates = past_groupmates(list, options[:past_groups])
  group_structure            = make_empty_group_structure(list.size, options[:target_size])
  corrected_group_structure  = correct_for_group_size_difference(group_structure, options[:max_difference])
  sorted_list                = sort(list, list_items_past_groupmates)
  groups                     = fill_group_structure(group_structure, sorted_list, list_items_past_groupmates)

  self.new(groups, list, list_items_past_groupmates)
end
new(groups, list, past_groupmates) click to toggle source
# File lib/garoupa.rb, line 27
def initialize(groups, list, past_groupmates)
  @groups          = groups
  @list            = list
  @past_groupmates = past_groupmates
end
past_groupmates(list, past_groups) click to toggle source
# File lib/garoupa.rb, line 18
def self.past_groupmates(list, past_groups)
  list.each_with_object( Hash.new ) do |list_item, previous_pairs|
    previous_pairs[list_item] = past_groupmates_for(list_item, past_groups)
  end
end

Private Class Methods

correct_for_group_size_difference(groups, max_difference = nil) click to toggle source
# File lib/garoupa.rb, line 55
def self.correct_for_group_size_difference(groups, max_difference = nil)
  return groups unless max_difference

  if difference_in_group_sizes(groups) > max_difference
    groups = disperse_last_group(groups)
  end
  groups
end
difference_in_group_sizes(groups) click to toggle source
# File lib/garoupa.rb, line 64
def self.difference_in_group_sizes(groups)
  sizes = groups.map(&:size)
  sizes.max - sizes.min
end
disperse_last_group(groups) click to toggle source
# File lib/garoupa.rb, line 69
def self.disperse_last_group(groups)
  last_group = groups.pop

  last_group.each_with_index do |element, index|
    groups[index] << element
  end

  groups
end
divide_list(list, group_size = nil) click to toggle source
# File lib/garoupa.rb, line 51
def self.divide_list(list, group_size = nil)
  list.each_slice(group_size || DEFAULT_GROUP_SIZE).to_a
end
fill_group_structure(group_structure, list, previous_pairs = {}) click to toggle source
# File lib/garoupa.rb, line 91
def self.fill_group_structure(group_structure, list, previous_pairs = {})
  list.each do |list_item|
    place_in_best_group(list_item, group_structure, previous_pairs)
  end

  group_structure
end
make_empty_group_structure(list_size, target_size = nil) click to toggle source
# File lib/garoupa.rb, line 79
def self.make_empty_group_structure(list_size, target_size = nil)
  empty_list = Array.new(list_size) { nil }
  empty_groups = divide_list(empty_list, target_size)
end
past_groupmates_for(element, past_groups = nil) click to toggle source
# File lib/garoupa.rb, line 84
def self.past_groupmates_for(element, past_groups = nil)
  return [] unless past_groups

  past_groups = past_groups.select { |group| group.include? element }
  past_groupmates = past_groups.flatten.uniq - [element]
end
place_in_best_group(list_item, group_structure, previous_pairs) click to toggle source
# File lib/garoupa.rb, line 99
def self.place_in_best_group(list_item, group_structure, previous_pairs)
  available_groups = group_structure.select { |group| group.include? nil }
  group_with_least_repeats = available_groups.min_by { |group| group & previous_pairs[list_item] }

  index_of_nil = group_with_least_repeats.index nil
  group_with_least_repeats[index_of_nil] = list_item

  return nil
end
sort(list, past_groupmates = nil) click to toggle source
# File lib/garoupa.rb, line 109
def self.sort(list, past_groupmates = nil)
  return list.shuffle unless past_groupmates

  list.shuffle.sort do |item_a, item_b|
    item_a_number_of_past_groupmates = past_groupmates.fetch(item_a, []).size
    item_b_number_of_past_groupmates = past_groupmates.fetch(item_b, []).size

    item_b_number_of_past_groupmates <=> item_a_number_of_past_groupmates
  end
end

Public Instance Methods

repeat_pairs() click to toggle source
# File lib/garoupa.rb, line 33
def repeat_pairs
  list.each_with_object( Hash.new ) do |list_item, repeat_pairs|
    repeat_pairs[list_item] = group_for(list_item) & past_groupmates[list_item]
  end
end
to_json() click to toggle source
# File lib/garoupa.rb, line 39
def to_json
  { :groups          => groups,
    :list            => list,
    :past_groupmates => past_groupmates,
    :repeat_pairs    => repeat_pairs }.to_json
end
to_s() click to toggle source
# File lib/garoupa.rb, line 46
def to_s
  groups.map.with_index(1) { |group, index| "#{index}. " + group.join(", ") }.join("\n")
end

Private Instance Methods

group_for(list_item) click to toggle source
# File lib/garoupa.rb, line 120
def group_for(list_item)
  groups.find { |group| group.include? list_item }
end