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

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more