Public
Edited
Sep 24, 2023
2 stars
Insert cell
Insert cell
Insert cell
Insert cell
teacherNames = ["Jara", "Gloria", "Nacho"]
Insert cell
studentNames = `
Laura
Natalie
Larissa
Maggie
Vanessa
Mariam
Greg
Ross
` // Stu, Jericho
.split(/[\n,]/)
.filter((name) => name.trim().length > 0)
Insert cell
usedGroups = [1,3,2, 4,5]
Insert cell
Insert cell
Insert cell
seed = 5
Insert cell
orderedGroupsets = {
let chosenGroupset = groupsets[0];
let remainingGroupsets = groupsets.slice(1);
const knownPairs = counter(pairs(chosenGroupset));
const orderedGroupsets = [chosenGroupset];

for (let i = 0, n = remainingGroupsets.length; i < n; ++i) {
const distances = remainingGroupsets.map((groupset) =>
distance(groupset, knownPairs)
);
const minDistance = Math.min(...distances);
const minDistanceIndex = distances.findIndex((d) => d === minDistance);
const chosenGroupset = remainingGroupsets[minDistanceIndex];
remainingGroupsets = remainingGroupsets.filter(
(_, j) => j != minDistanceIndex
);

pairs(chosenGroupset).forEach((pair) => (knownPairs[pair] += 1));
chosenGroupset.repeats = minDistance;
orderedGroupsets.push(chosenGroupset);
}

return orderedGroupsets;
}
Insert cell
groupsets = {
const knownGroups = [];
const groupsets = [];
const maxTries = 30;
const numRounds = 24;
d3.range(numRounds).forEach((groupIndex) => {
const groupset = nextGroupset(knownGroups, maxTries, groupIndex);
if (groupset) {
groupsets.push(groupset);
knownGroups.push(...groupset.map(group => group.join("-")));
}
});
return groupsets;
}
Insert cell
function nextGroupset(knownGroups, tryMax, groupIndex) {
let groupset;
let tryCount = 1;
do {
groupset = chunks(
shuffler(studentNames, seed + tryCount * 1e3 + groupIndex * 1e6),
teacherNames.length
).map((group) => group.sort((a, b) => d3.ascending(a, b))); // ensure element order doesn't matter

tryCount += 1;
} while (
tryCount < tryMax && // you haven't tried too many times yet
groupset.some((group) => knownGroups.includes(group.join("-"))) // and the current groupset still has repeat groups
);

if (
groupset &&
!groupset.some((group) => knownGroups.includes(group.join("-")))
) {
return groupset;
}
}
Insert cell
function counter(elements) {
const counts = {};
elements.forEach((d) => (counts[d] ? (counts[d] += 1) : (counts[d] = 1)));
return counts;
}
Insert cell
function distance(groupset, knownPairs) {
return pairs(groupset).reduce((a, x) => a + (knownPairs[x] || 0), 0);
}
Insert cell
function pairs(groupset) {
return groupset.flatMap((group) =>
combinations(group, 2).map((d) => d.join(""))
);
}
Insert cell
function combinations(elements, k) {
const result = [];

function helper(index, currentCombo) {
if (currentCombo.length === k) {
result.push(currentCombo);
return;
}
if (index === elements.length) return;

helper(index + 1, currentCombo.concat(elements[index]));
helper(index + 1, currentCombo);
}

helper(0, []);

return result;
}
Insert cell
shuffler = (arr, seed) => d3.shuffler(d3.randomLcg(seed))(arr.slice())
Insert cell
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more