Flipping my classroom with Ruby
I’m trying something funny in my mobile software development class. I scheduled it in the computer lab, not a lecture hall, and students are going to have to teach each other some things they prepared before we meet. Here’s what I’m telling them:
- You will do some preparation before each class, by watching a video or doing a reading. Half the class will do lesson A, half will do lesson B.
- You will teach other. A student from group A will be randomly paired with a student from group B. That’ll be the first 20 minutes.
- As pairs, you will work on hands-on, in-class exercises. These will take 30-40 minutes.
- We’ll end the class with demos and discussion.
- My in-class lecturing will be pretty short.
- You will be uncomfortable. I will be too. This will take some adjustment.
No good classroom management technique is complete without some supporting scripts. I’ve been meaning to learn Ruby for some time now. Every time I have a script to write, I suppress the temptation to code it up quickly in a language I know. Instead, I scrounge the Internet for the first Ruby construct that meets my purposes. For randomly pairing up students from groups A and B, I wrote this script:
#!/usr/bin/env ruby
# ----------------------------------------------------------------------------
# FILE: pair.rb
# AUTHOR: Chris Johnson
# DATE: Aug 11 2012
#
# A script for randomly pairing up students. Before class, students have been
# split up in two groups, A and B. Groups are formed such that each group
# contains a student from A and a student from B. In the event that the groups
# have different sizes, the number of groups formed is min(|A|, |B|). The
# leftover students, as well as any students who did not do the work required
# by the A and B treatments, are distributed evenly amongst these groups.
#
# Output is written to stdout and the file pair.log.
#
# Usage: pair.rb assignments.csv
#
# The first line of the CSV file is headers, and two columns are present. The
# first contains the student's name, and the second is one of 'a', 'b', 'x',
# and ''. Use 'x' to mark a student as present (needing a group) but neither A
# or B, and '' to mark a student absent. For example:
#
# name,group
# P. Pared,a
# A. Straight,b
# S. Pants,b
# T. Book,a
# Z. Brain,b
# D. Zeased,
# N. Competent,x
#
# A possible arrangement of the students is:
#
# T. Book, A. Straight, S. Pants
# P. Pared, Z. Brain, N. Competent
# ----------------------------------------------------------------------------
require 'rubygems'
require 'fastercsv'
file = ARGV[0]
as = Array.new
bs = Array.new
xs = Array.new
absents = Array.new
groups = Array.new
# Drop each student into one of the four groups.
FasterCSV.foreach(file, :headers => :first_row) do |line|
if not line[1]
absents << line[0]
elsif line[1] == "x"
xs << line[0]
elsif line[1] == "a"
as << line[0]
else line[1] == "b"
bs << line[0]
end
end
# Mix 'em up so we get random pairings.
as.shuffle!
bs.shuffle!
xs.shuffle!
# Put an A with a B as long as we have one of each.
while as.length > 0 and bs.length > 0
groups << "%s, %s" % [as.pop, bs.pop]
end
i = 0
# Distribute out the remaining As in the groups we've already made.
while as.length > 0
groups[i] = "%s, %s" % [groups[i], as.pop]
i = (i + 1) % groups.length
end
# Distribute out the remaining Bs in the groups we've already made.
while bs.length > 0
groups[i] = "%s, %s" % [groups[i], bs.pop]
i = (i + 1) % groups.length
end
# Distribute out the students who didn't do their work.
while xs.length > 0
groups[i] = "%s, %s" % [groups[i], xs.pop]
i = (i + 1) % groups.length
end
# Show the groups.
puts groups
logFile = File.new("pair.log", "w")
logFile.puts groups
logFile.close
If I’m violating the Ruby way somewhere, I’d welcome your input.
Revision – August 21, 2012
Based on the comments, I’ve revised my script:
#!/usr/bin/env ruby
# ----------------------------------------------------------------------------
# FILE: pair.rb
# AUTHOR: Chris Johnson
# DATE: Aug 11 2012
#
# A script for randomly pairing up students. Before class, students have been
# split up in two groups, A and B. Groups are formed such that each group
# contains a student from A and a student from B. In the event that the groups
# have different sizes, the number of groups formed is min(|A|, |B|). The
# leftover students, as well as any students who did not do the work required
# by the A and B treatments, are distributed evenly amongst these groups.
#
# Output is written to stdout and the file pair.log.
#
# Usage: pair.rb assignments.csv
#
# The first line of the CSV file is headers, and two columns are present. The
# first contains the student's name, and the second is one of 'a', 'b', 'x',
# and ''. Use 'x' to mark a student as present (needing a group) but neither A
# or B, and '' to mark a student absent. For example:
#
# name,group
# P. Pared,a
# A. Straight,b
# S. Pants,b
# T. Book,a
# Z. Brain,b
# D. Zeased,
# N. Competent,x
#
# A possible arrangement of the students is:
#
# T. Book, A. Straight, S. Pants
# P. Pared, Z. Brain, N. Competent
# ----------------------------------------------------------------------------
require 'rubygems'
require 'fastercsv'
class Pairer
@lastFilledAt = 0
def initialize(file)
lists = {
'a' => Array.new,
'b' => Array.new,
'x' => Array.new,
'' => Array.new
}
# Drop each student into one of the four groups.
FasterCSV.foreach(file, :headers => :first_row) do |line|
name = line[0]
group = line[1]
lists[group] << name
end
# Mix 'em up so we get random pairings.
lists['a'].shuffle!
lists['b'].shuffle!
lists['x'].shuffle!
# Put an A with a B as long as we have one of each.
@groups = Array.new
while lists['a'].length > 0 and lists['b'].length > 0
@groups << "#{lists['a'].pop}, #{lists['b'].pop}"
end
# Distribute out the remaining As, Bs, and Xs in the groups we've already
# made.
@lastFilledAt = 0
distribute(lists['a'])
distribute(lists['b'])
distribute(lists['x'])
end
def distribute(list)
while list.length > 0
@groups[@lastFilledAt] = "#{@groups[@lastFilledAt]}, #{list.pop}"
@lastFilledAt = (@lastFilledAt + 1) % @groups.length
end
end
def log
# Show the groups.
puts @groups
logFile = File.new("pair.log", "w")
logFile.puts @groups
logFile.close
end
end
pairer = Pairer.new(ARGV[0])
pairer.log