Public
Edited
Apr 20, 2024
1 fork
Importers
Insert cell
Insert cell
viewof newGroup = randomGroup({data:exampleData, numGroup:2, dataHeight:200, outputHeight:400, outputWidth:600});
Insert cell
exampleData = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N"];
Insert cell
newGroup
Insert cell
Insert cell
function randomGroup(
{
data=[],
numGroup = data.length > 2 ? parseInt(data.length / 2) : 1,
dataHeight = 200,
outputHeight = 500,
outputWidth = 400,
dataDisplay = true,
outputDisplay = true,
} = {}
) {
// Check user input
if (numGroup > data.length) {
numGroup = data.length;
} else if (numGroup < 1) {
numGroup = 1;
}
// Check if data is not an array
if (!Array.isArray(data)) {
throw new Error("Data must be an array.");
return;
}
let groupResult = [];

const onDataChange = (event) => {
data = event.target.value
.split("\n")
.map((item) => item.trim())
.filter((item) => item !== "");
numGroup = data.length > 2 ? parseInt(data.length / 2) : 1;
setNumGroup();
generate();
};

const onNumGroupChange = (event) => {
numGroup = parseInt(event.target.value);
if (numGroup > data.length) {
numGroup = data.length;
} else if (numGroup < 1) {
numGroup = 1;
}
setNumGroup();
generate();
};

const onSliderChange = (event) => {
numGroup = parseInt(event.target.value);
setNumGroup();
generate();
};

const setNumGroup = function () {
numGroupInput.querySelector("#numGroupInput").value = numGroup;
sliderInput.querySelector("#numGroupSlider").max = data.length;
sliderInput.querySelector("#numGroupSlider").value = numGroup;
};

const getGroup = function (__data) {
let result = [];
// Protect the data by clone a new one
const _data = __data.slice(0);
if (_data.length === 0) {
return result;
}
const shuffledData = _data.sort(() => Math.random() - 0.5);
for (let i = 0; i < numGroup; i++) {
result.push([]);
}
let currentIndex = 0;

// Create a slots for remaining elements
const remain = Array.from({ length: numGroup }, (_, index) => index);
shuffledData.forEach((item, i) => {
result[currentIndex].push(item);
if (
i + 1 >= parseInt(_data.length / numGroup) * numGroup &&
_data.length % numGroup != 0
) {
const randomIndex = Math.floor(Math.random() * remain.length);
currentIndex = remain[randomIndex];
remain.splice(randomIndex, 1);
} else {
currentIndex = (currentIndex + 1) % numGroup;
}
});
return result;
};

const generate = function () {
groupResult = getGroup(data);
renderGroupTable();
target.value = groupResult;
target.dispatchEvent(new CustomEvent("input", { bubbles: true }));
};

const renderGroupTable = function () {
groupTable.innerHTML = "";
groupResult.forEach((group, index) => {
const table = document.createElement("table");
const header = table.createTHead();
const row = header.insertRow();
const cell = row.insertCell();
cell.textContent = `Group ${index + 1}`;
group.forEach((member) => {
const row = table.insertRow();
const cell = row.insertCell();
cell.textContent = member;
});
groupTable.appendChild(table);
});
};

const dataArea = htl.html`
<textarea id="dataInput" style="width: ${width}; height: ${dataHeight}px;" oninput=${onDataChange}>${
data.length > 0 ? data.join("\n") : ""
}</textarea>
`;

const numGroupInput = htl.html`
<input type="number" id="numGroupInput" style="width: 50px;" value="${numGroup}" onchange=${onNumGroupChange}>
`;

const sliderInput = htl.html`
<input type="range" id="numGroupSlider" style="width: 150px;" min="1" max="${data.length}" value="${numGroup}" oninput=${onSliderChange}>
`;

const regenerateButton = htl.html`
<button onclick=${generate}>Regenerate</button>
`;
const groupTable = htl.html`
<div id="groupTable"></div>
`;

const target = htl.html`
<div>
${dataDisplay ? dataArea : ''}
<div>
<label for="numGroup">Number of Groups:</label>
${numGroupInput}
${sliderInput}
${regenerateButton}
</div>
<div id="groupTable" style="width:${outputWidth}px; max-height: ${outputHeight}px; overflow-y: auto;">
${outputDisplay ? groupTable : ''}
</div>
</div>
`;
target.value = groupResult;
generate();
return target;
}
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