如何根据给定数字增加值将数组拆分为多个数组?
How to split an array into a number of arrays based on increasing value by a given number?
我编写了以下函数:
const trends = hits.reduce((arr, curr, index, array) => {
if (arr.includes(curr)) return arr
if (curr + 1 === array[index + 1]) arr.push(curr, array[index + 1]);
return arr;
}, []);
要点是,如果一个数组包含一个递增 1 的数字序列,那么这个 return 就是一个具有这些值的新数组。
例如:[1, 2, 3, 6, 10]
会 return [1, 2, 3]
.
问题是:如果有多个序列,我想将它放在一个单独的数组中(或子数组的数组中)。此时,该函数执行以下操作 [1, 2, 3, 6, 7, 8]
。我也无法预测可能会有多少种趋势。我怎样才能做到这一点?
您可以让累加器成为部分结果数组和先前值的组合(以便于访问它)。为了保持代码简单,您可以将每个当前值添加到最后一个子数组,或者作为它自己的子数组。 reduce
完成后,可以踢出那些只有一个值的子数组:
let hits = [2, 4, 5, 6, 8, 10, 11, 12, 14];
const trends = hits.reduce(([arr, prev], curr, index, array) => {
if (prev + 1 == curr) arr[arr.length-1].push(curr);
else arr.push([curr]);
return [arr, curr];
}, [[], NaN])[0].filter(row => row.length > 1);
console.log(trends);
一种直接的方法,基于优先级不能为 changed/swapped 的两个条件,它实际上也读取了它的作用...
function collectItemSequences(list, item, idx, arr) {
if ((item - 1) === arr[idx - 1]) {
// in case of a predecessor ...
// ... push item into the most recent sequence list.
list[list.length - 1].push(item);
} else if ((item + 1) === arr[idx + 1]) {
// else, in case of a successor ...
// ... create a new sequence list with its 1st item.
list.push([ item ]);
}
return list;
}
console.log(
[2, 4, 6, 8, 10, 12, 14].reduce(collectItemSequences, [])
);
console.log(
[2, 4, 5, 6, 8, 10, 11, 12, 14].reduce(collectItemSequences, [])
);
console.log(
[1, 2, 4, 5, 6, 8, 10, 11, 12, 14, 15].reduce(collectItemSequences, [])
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
基于上述方法,可以实现一种更通用的方法,它允许配置如何分别计算当前项目的序列前驱 序列后继 ...
function collectItemSequencesByConditions(collector, item, idx, arr) {
const { getPredecessor, getSuccessor, list } = collector;
if (getPredecessor(item) === arr[idx - 1]) {
// push item into the most recent sequence list.
list[list.length - 1].push(item);
} else if (getSuccessor(item) === arr[idx + 1]) {
// create a new sequence list with its 1st item.
list.push([ item ]);
}
return collector;
}
const conditions = {
getPredecessor: currentItem => currentItem - 2,
getSuccessor: currentItem => currentItem + 2,
};
console.log(
[2, 4, 6, 8, 10, 12, 14].reduce(
collectItemSequencesByConditions,
{ ...conditions, list: [] },
).list
);
console.log(
[2, 4, 5, 6, 8, 10, 11, 12, 14].reduce(
collectItemSequencesByConditions,
{ ...conditions, list: [] },
).list
);
console.log(
[1, 2, 4, 5, 6, 8, 10, 11, 12, 14, 15].reduce(
collectItemSequencesByConditions,
{ ...conditions, list: [] },
).list
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
编辑
OP 的问题
I set up two pair of conditions, one for item - 1
, item + 1
, second pair respectively for - 10
, + 10
. The hits array was [22, 31, 32, 33, 42, 52]
. I turned your console.logs
into const variable = hits.reduce...
so on. Then I returned both variables. The results were [31, 32, 33]
and [42, 52]
. The expected outcome for second is of course [22, 33, 42, 52]
.
首先,OP 很可能意味着 [22, 32, 42, 52]
。
其次...
不,数学是可靠的。而且算法不能被欺骗。适用于有效 predecessors/successors 的规则是无情的。因此 “ [22, 31, 32, 33, 42, 52]
和 +/- 10
的预期结果是 [42, 52]
而不是 [22, 32, 42, 52]
.
为什么?.. [22, 31, 32, 33, 42, 52]
的第二个值是 31
,它打破了任何可能的序列( OP 预期 22
、32
)。因此它不是一个有效的 predecessor/successor 序列。
这里有一些测试用例...
console.log(
"for [22, 31, 32, 33, 42, 52] and [-1 , +1]",
"\nexpect: '[[31,32,33]]' ?",
JSON.stringify([22, 31, 32, 33, 42, 52].reduce(
collectItemSequencesByConditions, {
getPredecessor: currentItem => currentItem - 1,
getSuccessor: currentItem => currentItem + 1,
list: [],
}
).list) === '[[31,32,33]]'
);
console.log(
[22, 31, 32, 33, 42, 52].reduce(
collectItemSequencesByConditions, {
getPredecessor: currentItem => currentItem - 1,
getSuccessor: currentItem => currentItem + 1,
list: [],
}
).list
);
console.log(
"for [22, 31, 32, 33, 42, 52] and [-10 , +10]",
"\nexpect: '[[42,52]]' ?",
JSON.stringify([22, 31, 32, 33, 42, 52].reduce(
collectItemSequencesByConditions, {
getPredecessor: currentItem => currentItem - 10,
getSuccessor: currentItem => currentItem + 10,
list: [],
}
).list) === '[[42,52]]'
);
console.log(
[22, 31, 32, 33, 42, 52].reduce(
collectItemSequencesByConditions, {
getPredecessor: currentItem => currentItem - 10,
getSuccessor: currentItem => currentItem + 10,
list: [],
}
).list
);
console.log(
"for [21, 22, 32, 33, 42, 52] and [-10 , +10]",
"\nexpect: '[[22,32],[42,52]]' ?",
JSON.stringify([21, 22, 32, 33, 42, 52].reduce(
collectItemSequencesByConditions, {
getPredecessor: currentItem => currentItem - 10,
getSuccessor: currentItem => currentItem + 10,
list: [],
}
).list) === '[[22,32],[42,52]]'
);
console.log(
[21, 22, 32, 33, 42, 52].reduce(
collectItemSequencesByConditions, {
getPredecessor: currentItem => currentItem - 10,
getSuccessor: currentItem => currentItem + 10,
list: [],
}
).list
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
<script>
function collectItemSequencesByConditions(collector, item, idx, arr) {
const { getPredecessor, getSuccessor, list } = collector;
if (getPredecessor(item) === arr[idx - 1]) {
// push item into the most recent sequence list.
list[list.length - 1].push(item);
} else if (getSuccessor(item) === arr[idx + 1]) {
// create a new sequence list with its 1st item.
list.push([ item ]);
}
return collector;
}
</script>
我编写了以下函数:
const trends = hits.reduce((arr, curr, index, array) => {
if (arr.includes(curr)) return arr
if (curr + 1 === array[index + 1]) arr.push(curr, array[index + 1]);
return arr;
}, []);
要点是,如果一个数组包含一个递增 1 的数字序列,那么这个 return 就是一个具有这些值的新数组。
例如:[1, 2, 3, 6, 10]
会 return [1, 2, 3]
.
问题是:如果有多个序列,我想将它放在一个单独的数组中(或子数组的数组中)。此时,该函数执行以下操作 [1, 2, 3, 6, 7, 8]
。我也无法预测可能会有多少种趋势。我怎样才能做到这一点?
您可以让累加器成为部分结果数组和先前值的组合(以便于访问它)。为了保持代码简单,您可以将每个当前值添加到最后一个子数组,或者作为它自己的子数组。 reduce
完成后,可以踢出那些只有一个值的子数组:
let hits = [2, 4, 5, 6, 8, 10, 11, 12, 14];
const trends = hits.reduce(([arr, prev], curr, index, array) => {
if (prev + 1 == curr) arr[arr.length-1].push(curr);
else arr.push([curr]);
return [arr, curr];
}, [[], NaN])[0].filter(row => row.length > 1);
console.log(trends);
一种直接的方法,基于优先级不能为 changed/swapped 的两个条件,它实际上也读取了它的作用...
function collectItemSequences(list, item, idx, arr) {
if ((item - 1) === arr[idx - 1]) {
// in case of a predecessor ...
// ... push item into the most recent sequence list.
list[list.length - 1].push(item);
} else if ((item + 1) === arr[idx + 1]) {
// else, in case of a successor ...
// ... create a new sequence list with its 1st item.
list.push([ item ]);
}
return list;
}
console.log(
[2, 4, 6, 8, 10, 12, 14].reduce(collectItemSequences, [])
);
console.log(
[2, 4, 5, 6, 8, 10, 11, 12, 14].reduce(collectItemSequences, [])
);
console.log(
[1, 2, 4, 5, 6, 8, 10, 11, 12, 14, 15].reduce(collectItemSequences, [])
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
基于上述方法,可以实现一种更通用的方法,它允许配置如何分别计算当前项目的序列前驱 序列后继 ...
function collectItemSequencesByConditions(collector, item, idx, arr) {
const { getPredecessor, getSuccessor, list } = collector;
if (getPredecessor(item) === arr[idx - 1]) {
// push item into the most recent sequence list.
list[list.length - 1].push(item);
} else if (getSuccessor(item) === arr[idx + 1]) {
// create a new sequence list with its 1st item.
list.push([ item ]);
}
return collector;
}
const conditions = {
getPredecessor: currentItem => currentItem - 2,
getSuccessor: currentItem => currentItem + 2,
};
console.log(
[2, 4, 6, 8, 10, 12, 14].reduce(
collectItemSequencesByConditions,
{ ...conditions, list: [] },
).list
);
console.log(
[2, 4, 5, 6, 8, 10, 11, 12, 14].reduce(
collectItemSequencesByConditions,
{ ...conditions, list: [] },
).list
);
console.log(
[1, 2, 4, 5, 6, 8, 10, 11, 12, 14, 15].reduce(
collectItemSequencesByConditions,
{ ...conditions, list: [] },
).list
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
编辑
OP 的问题
I set up two pair of conditions, one for item
- 1
, item+ 1
, second pair respectively for- 10
,+ 10
. The hits array was[22, 31, 32, 33, 42, 52]
. I turned yourconsole.logs
intoconst variable = hits.reduce...
so on. Then I returned both variables. The results were[31, 32, 33]
and[42, 52]
. The expected outcome for second is of course[22, 33, 42, 52]
.
首先,OP 很可能意味着 [22, 32, 42, 52]
。
其次...
不,数学是可靠的。而且算法不能被欺骗。适用于有效 predecessors/successors 的规则是无情的。因此 “ [22, 31, 32, 33, 42, 52]
和 +/- 10
的预期结果是 [42, 52]
而不是 [22, 32, 42, 52]
.
为什么?.. [22, 31, 32, 33, 42, 52]
的第二个值是 31
,它打破了任何可能的序列( OP 预期 22
、32
)。因此它不是一个有效的 predecessor/successor 序列。
这里有一些测试用例...
console.log(
"for [22, 31, 32, 33, 42, 52] and [-1 , +1]",
"\nexpect: '[[31,32,33]]' ?",
JSON.stringify([22, 31, 32, 33, 42, 52].reduce(
collectItemSequencesByConditions, {
getPredecessor: currentItem => currentItem - 1,
getSuccessor: currentItem => currentItem + 1,
list: [],
}
).list) === '[[31,32,33]]'
);
console.log(
[22, 31, 32, 33, 42, 52].reduce(
collectItemSequencesByConditions, {
getPredecessor: currentItem => currentItem - 1,
getSuccessor: currentItem => currentItem + 1,
list: [],
}
).list
);
console.log(
"for [22, 31, 32, 33, 42, 52] and [-10 , +10]",
"\nexpect: '[[42,52]]' ?",
JSON.stringify([22, 31, 32, 33, 42, 52].reduce(
collectItemSequencesByConditions, {
getPredecessor: currentItem => currentItem - 10,
getSuccessor: currentItem => currentItem + 10,
list: [],
}
).list) === '[[42,52]]'
);
console.log(
[22, 31, 32, 33, 42, 52].reduce(
collectItemSequencesByConditions, {
getPredecessor: currentItem => currentItem - 10,
getSuccessor: currentItem => currentItem + 10,
list: [],
}
).list
);
console.log(
"for [21, 22, 32, 33, 42, 52] and [-10 , +10]",
"\nexpect: '[[22,32],[42,52]]' ?",
JSON.stringify([21, 22, 32, 33, 42, 52].reduce(
collectItemSequencesByConditions, {
getPredecessor: currentItem => currentItem - 10,
getSuccessor: currentItem => currentItem + 10,
list: [],
}
).list) === '[[22,32],[42,52]]'
);
console.log(
[21, 22, 32, 33, 42, 52].reduce(
collectItemSequencesByConditions, {
getPredecessor: currentItem => currentItem - 10,
getSuccessor: currentItem => currentItem + 10,
list: [],
}
).list
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
<script>
function collectItemSequencesByConditions(collector, item, idx, arr) {
const { getPredecessor, getSuccessor, list } = collector;
if (getPredecessor(item) === arr[idx - 1]) {
// push item into the most recent sequence list.
list[list.length - 1].push(item);
} else if (getSuccessor(item) === arr[idx + 1]) {
// create a new sequence list with its 1st item.
list.push([ item ]);
}
return collector;
}
</script>