function randomGroup(
{
data=[],
numGroup = data.length > 2 ? parseInt(data.length / 2) : 1,
dataHeight = 200,
outputHeight = 500,
outputWidth = 400,
dataDisplay = true,
outputDisplay = true,
} = {}
) {
if (numGroup > data.length) {
numGroup = data.length;
} else if (numGroup < 1) {
numGroup = 1;
}
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 = [];
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;
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;
}