我有这个程序,它目前可以找到重复项并使用 dom 将它们打印出来。我正在编辑它,以便它还显示输入数组中根本没有出现的数字以及输入数组中只出现过一次的数字。不包括 0 作为未发生的数字。此外,将变量设置为最大数字范围,我们检查输入数组中是否出现数字。输出的切片工作正常,我基本上只是将只出现 0 次和 1 次的数字添加到输出中。我看不出如何正确执行此操作。请协助。谢谢。
示例数组输入 [
4,4,4,4,2,4,4,4,4,4,2,2,2,3,2,2,2,2,2,3,3,3,7,3,3,3,3,1,6,6,6,1,1,1,7,7,7,7,6,6,5]当前示例输出:(部分变量 = 3):
4 - 9 次 2 - 8 次
3 - 7 次 1 - 6 次
7 - 5 次 6 - 4 次
期望的输出:示例 1(部分变量 = 3,数字范围 = 9):
4 - 9 次 2 - 8 次 3 - 7 次
1 - 6 次7 - 5 次 6 - 4 次
5 - 1 次 8 - 0 次9 - 0 次
期望输出:示例 2(部分变量 = 3,数字范围 = 21):
4 - 9 次 2 - 8 次 3 - 7 次 1 - 6 次 7 - 5 次6 - 4 次 5 - 1 次
8 - 0 次 9 - 0 次 10 - 0 次 11 - 0 次 12 - 0 次 13 - 0 次14 - 0 次
15 - 0 次 16 - 0 次 17 - 0 次 18 - 0 次 19 - 0 次 20 - 0 次21 - 0 次
//Count how many times each number shows up
//const duplicateArr2 = [1, 1, 1, 1, 1, 100, 3, 5, 2, 5, 2, 23, 23, 23, 23, 23];
//const duplicateArr1 = [5, 3, 7, 4, 7, 5, 3, 2, 7, 3, 2];
//const duplicateArr2 = [4,4,4,4,2,4,4,4,4,4,2,2,2,3,2,2,2,2,3,3,3,7,3,3,3,1,6,6,1,1,1,1,1,7,7,7,7,6,6,55,55,67,67,45,54,45,54];
//const duplicateArr2 = [4,4,4,4,2,4,4,4,4,4,2,2,2,3,2,2,2,2,3,3,3,7,3,3,3,1,6,6,1,1,1,1,1,7,7,7,7,6,6,55,55,67,67,45,54,45,54,100,100,200,200,300,300];
//const duplicateArr2 = searchednumbers;
const duplicateArr2 = [4, 4, 4, 4, 2, 4, 4, 4, 4, 4, 2, 2, 2, 3, 2, 2, 2, 2, 3, 3, 3, 7, 3, 3, 3, 1, 6, 6, 1, 1, 1, 1, 1, 7, 7, 7, 7, 6, 6, 5]
const getArrayOfDuplicated = array => {
const hash = array.reduce((a, c) => (a[c] = ++a[c] || 1, a), {});
return Object.entries(hash)
.filter(([k, v]) => v > 1)
.sort(([ak, av], [bk, bv]) => bv - av)
.reduce((a, [k, v]) => [...a, `${k} - ${v} times`], [])
};
// given a number of items to be sectioned into a certain number of groups
// returns a list of length nGroups with the number of items in each group
// such that at least (nGroups - 1) groups contain an equal number of items
// eg. getGrouping(10, 2) -> [5, 5]
// eg. getGrouping(10, 6) -> [1, 1, 1, 1, 1, 5]
const getGrouping = (nItems, nGroups) => {
if (nGroups > nItems)
return Array(nItems).fill(1);
else if (!(nItems % nGroups))
return Array(nGroups).fill(parseInt(nItems / nGroups));
else {
let numberOfEqualGroups = nGroups - 1;
var itemsPerEqualGroup;
if (!(nItems % (nGroups - 1)))
itemsPerEqualGroup = parseInt(nItems / (nGroups - 1)) - 1;
else
itemsPerEqualGroup = parseInt(nItems / (nGroups - 1));
equalGroups = Array(numberOfEqualGroups).fill(parseInt(itemsPerEqualGroup));
remainder = nItems - itemsPerEqualGroup * numberOfEqualGroups;
return equalGroups.concat(remainder);
}
}
// takes an array and formats it into sections according to grouping
// returns a string with a newline after each line and two new lines between sections
const formatGrouping = (array, grouping) => {
var outputString = ""
var linesDone = 0;
for (var section = 0; section < grouping.length; section++) {
for (var line = 0; line < grouping[section]; line++) {
outputString += array[linesDone] + '<br>';
linesDone += 1;
}
outputString += '<br>';
}
return outputString;
};
var numberOfSections = 3;
result = getArrayOfDuplicated(duplicateArr2);
document.getElementById("jsresultsoutput").innerHTML = formatGrouping(result, getGrouping(result.length, numberOfSections));
<p id="jsresultsoutput"></p>
你的代码几乎是对的。你错过了一件事,你有一个不必要的filter
.
缺失:在进行计数之前,您需要创建数字地图(1 到numbersrange
)。否则,出现次数为 0 的数字将不会显示。我这样做过
const mapOfNumbers = new Array(numbersrange + 1).fill(0).reduce((acc, _, i) => (acc[i] = 0, acc), {});
delete mapOfNumbers[0];
额外:不需要.filter(([k, v]) => v > 1)
,因为您希望1
和0
发生。
//Count how many times each number shows up
//const duplicateArr2 = [1, 1, 1, 1, 1, 100, 3, 5, 2, 5, 2, 23, 23, 23, 23, 23];
//const duplicateArr1 = [5, 3, 7, 4, 7, 5, 3, 2, 7, 3, 2];
//const duplicateArr2 = [4,4,4,4,2,4,4,4,4,4,2,2,2,3,2,2,2,2,3,3,3,7,3,3,3,1,6,6,1,1,1,1,1,7,7,7,7,6,6,55,55,67,67,45,54,45,54];
//const duplicateArr2 = [4,4,4,4,2,4,4,4,4,4,2,2,2,3,2,2,2,2,3,3,3,7,3,3,3,1,6,6,1,1,1,1,1,7,7,7,7,6,6,55,55,67,67,45,54,45,54,100,100,200,200,300,300];
//const duplicateArr2 = searchednumbers;
const duplicateArr2 = [4, 4, 4, 4, 2, 4, 4, 4, 4, 4, 2, 2, 2, 3, 2, 2, 2, 2, 3, 3, 3, 7, 3, 3, 3, 1, 6, 6, 1, 1, 1, 1, 1, 7, 7, 7, 7, 6, 6, 5]
const getArrayOfDuplicated = (array, numbersrange) => {
const mapOfNumbers = new Array(numbersrange + 1).fill(0).reduce((acc, _, i) => (acc[i] = 0, acc), {});
delete mapOfNumbers[0];
const hash = array.reduce((a, c) => (a[c] = ++a[c] || 1, a), mapOfNumbers);
return Object.entries(hash)
.sort(([ak, av], [bk, bv]) => bv - av)
.reduce((a, [k, v]) => [...a, `${k} - ${v} times`], [])
};
// given a number of items to be sectioned into a certain number of groups
// returns a list of length nGroups with the number of items in each group
// such that at least (nGroups - 1) groups contain an equal number of items
// eg. getGrouping(10, 2) -> [5, 5]
// eg. getGrouping(10, 6) -> [1, 1, 1, 1, 1, 5]
const getGrouping = (nItems, nGroups) => {
if (nGroups > nItems)
return Array(nItems).fill(1);
else if (!(nItems % nGroups))
return Array(nGroups).fill(parseInt(nItems / nGroups));
else {
let numberOfEqualGroups = nGroups - 1;
var itemsPerEqualGroup;
if (!(nItems % (nGroups - 1)))
itemsPerEqualGroup = parseInt(nItems / (nGroups - 1)) - 1;
else
itemsPerEqualGroup = parseInt(nItems / (nGroups - 1));
equalGroups = Array(numberOfEqualGroups).fill(parseInt(itemsPerEqualGroup));
remainder = nItems - itemsPerEqualGroup * numberOfEqualGroups;
return equalGroups.concat(remainder);
}
}
// takes an array and formats it into sections according to grouping
// returns a string with a newline after each line and two new lines between sections
const formatGrouping = (array, grouping) => {
var outputString = ""
var linesDone = 0;
for (var section = 0; section < grouping.length; section++) {
for (var line = 0; line < grouping[section]; line++) {
outputString += array[linesDone] + '<br>';
linesDone += 1;
}
outputString += '<br>';
}
return outputString;
};
var numberOfSections = 3;
var numbersrange = 9;
result = getArrayOfDuplicated(duplicateArr2, numbersrange);
document.getElementById("jsresultsoutput").innerHTML = formatGrouping(result, getGrouping(result.length, numberOfSections));
<p id="jsresultsoutput"></p>
此外,阅读有关您问题的评论将为您提供缺少的完整解决方案。你可以说我已经把评论汇编成一个答案。
不能很好地遵循 OP 代码,但理解目标:
-
输入是一个任意长度的数字数组 - 每个数字在 1 到
n
的范围内。 -
输出为以下组:
- 排除的未包含在输入数组中但在给定范围内的数字。
- 包含在输入数组中且在给定范围内的唯一数字。
- 包含在输入数组中且在给定范围内的重复数字。
-
每组重复项也必须列出其总数。
我没有为每个数字生成 DOM,而是开发了一个表单,该表单清楚地定义了逻辑流中所需的参数。约束和值如下所示:
-
用户设置数字范围的最小/最大值。最小值可以设置为 [
1
-99
]/最大值可以设置为 [minimum value +1
-100
]。 -
下一个用户可以通过输入值并单击"添加"按钮来添加任意数量的数字。如果用户输入的数字超过既定范围,则输入将自动相应地限制为最大值/最小值。
-
最后,用户单击">排序"按钮。最后 4 个字段将显示输出(2. 到4.前面已经描述过):
1. 输入数组将数字显示为有序数组。
2. 排除,3.独一无二,4.重复
-
用户可以返回到向结果中添加其他数字,或者通过单击">清除"按钮或简单地设置新范围来重新开始。
尽管使用事件属性因其固有的局限性而受到不欢迎 - 在表单上使用事件属性将输入与输出相关联,提供适当的行为和约束等实际上是有利的。oninput
、onchange
和onclick
用于用户交互,并且仅与主要功能有少量的参与。
只是关于功能的快速概述:
-
对
<form>
及其表单控件(即input
、output
、button
和fieldset
)的引用可以通过HTMLFormElement和HTMLFormControlsCollection接口实现。语法简洁,元素范围最优:document.getElementById('formID').querySelectorAll('input, button, select, textarea, output, fieldset');
vs.
document.forms.formID.elements;
-
数字的范围由生成器函数(
*generateRange()
)提供,该函数返回给定最小值和最大值(包括最大值)之间的连续数字数组。 -
然后,一旦生成范围数组,它就会通过
for...of
循环运行。在每次迭代中,当前数字作为值为0
的键.set()
到 ES6Map()
中。 -
接下来,输入数组通过
for...of
循环运行。在每次迭代中,在Map()
中找到该数字作为键,然后关联值增加 1。 -
我们几乎不费吹灰之力就得到了一个
Map()
,它将给定范围内的每个数字都作为键,其值为0
(排除)、1
(唯一)或2+
(重复)。 -
最后,组显示在表单中。
const ui = document.forms[0].elements;
const stringToNumber = str => parseInt(str, 10);
const isNumber = val => Number(parseFloat(val)) === val;
function* generateRange(min, max) {
while (min < max) {
yield min;
min += 1;
}
}
const displayRange = map => {
let outputs = Array.from(ui.data);
for (let i = 2; i < 5; i++) {
outputs[i].textContent = '';
}
for (let [number, count] of map.entries()) {
if (count === 0) {
ui.zero.textContent += `${number} `;
} else if (count === 1) {
ui.one.textContent += `${number} `;
} else {
ui.more.insertAdjacentHTML('beforeend', `<label>
${number}: ${count} times</label>`);
}
}
}
const clearData = e => {
const fields = e.currentTarget.elements.data;
for (let i = 0; i < fields.length; i++) {
fields[i].textContent = '';
}
}
const addNumber = e => {
let number = e.target.previousElementSibling.valueAsNumber;
if (number > ui.max.valueAsNumber) {
number = ui.max.valueAsNumber;
} else if (number < ui.min.valueAsNumber) {
number = ui.min.valueAsNumber;
} else {
number = number;
}
ui.input.insertAdjacentText('beforeend', ` ${number} `);
}
const sortArray = e => {
let string = ui.input.textContent;
let numbers = string.split(' ').map(stringToNumber).filter(num => isNumber(num));
let array = numbers.sort((a, b) => a - b);
let min = ui.min.valueAsNumber;
let max = ui.max.valueAsNumber + 1;
let range = Array.from(generateRange(min, max));
let map = new Map();
for (let r of range) {
map.set(r, 0);
}
for (let a of array) {
map.set(a, (map.get(a) + 1));
}
ui.array.textContent = '';
ui.array.textContent = JSON.stringify(array);
return displayRange(map);
}
ui.add.onclick = addNumber;
ui.sort.onclick = sortArray;
document.forms[0].onreset = clearData;
:root {
font: 400 16px/1 Consolas;
}
html,
body {
width: 100%;
height: 100%;
}
body {
overflow-x: hidden;
overflow-y: scroll;
padding: 5vh 3vw 10vh 0;
}
main {
width: 96vw;
height: auto;
}
#freq {
width: 98%;
}
output,
input,
button,
label {
font: inherit;
display: inline-block;
line-height: 30px;
height: 30px;
vertical-align: middle;
}
fieldset {
max-width: 100%;
margin-bottom: 4vh;
}
#input,
#array,
#zero,
#one,
#more {
min-height: 60px;
height: auto;
word-break: break-word;
}
#range input {
width: 30%;
}
#range output {
width: 3ch;
padding: 0 5px;
}
#num {
text-align: center;
width: 5ch;
height: 24px;
line-height: 24px;
}
#numbers input,
#numbers button {
margin-bottom: 8px
}
#sort,
[type=reset],
sub {
float: right;
}
button {
padding: 0 3px;
font-size: 1.2rem;
}
#more label {
display: block;
}
<main>
<form id='freq' oninput='max.min = min.valueAsNumber+1; maxOut.value = max.value;' onchange='num.min = min.value; num.max = max.value'>
<fieldset id='range' onclick="num.value = ''; input.textContent = ''; array.textContent = ''; zero.textContent = ''; one.textContent = ''; more.textContent = '';">
<legend>Define Number Range</legend>
<label for='min'>Min: </label><input id='min' type='range' min='1' max='99' oninput='minOut.value = this.value;' value='1'><output id='minOut' for='min num'>1</output>
<label for='max'>Max: </label><input id='max' type='range' max='100' oninput='maxOut.value = this.value'><output id='maxOut' for='max num'></output>
<sub>min: 1 / max: 100</sub>
</fieldset>
<fieldset id='numbers'>
<legend>Add & Sort Numbers</legend>
<input id='num' type='number'>
<button id='add' type='button'>Add</button>
<button type='reset'>Clear</button>
<button id='sort' type='button'>Sort</button>
<fieldset>
<output id='input' name='data'></output>
</fieldset>
</fieldset>
<fieldset id='output'>
<legend>Output</legend>
<fieldset>
<legend>Input Array</legend>
<output id='array' name='data'></output>
</fieldset>
<fieldset>
<legend>Excluded</legend>
<output id='zero' name='data'></output>
</fieldset>
<fieldset>
<legend>Unique</legend>
<output id='one' name='data'></output>
</fieldset>
<fieldset>
<legend>Duplicated</legend>
<output id='more' name='data'></output>
</fieldset>
</fieldset>
</form>
</main>