很难用标题来描述它,但是从这里的描述和代码中应该很清楚。我正在尝试从一组峰中选择一个数组中最高的数字,然后转到下一组并从下一组高点中获取下一个峰数。
例如在此数组中:
const arr = [939, 1301, 253, 1380, 1037, 2279, 2462, 2193, 2121, 1424, 506, 2411, 2456, 2295, 915, 1276, 1532, 1359, 985, 2182, 2407, 2103, 2392, 2294, 765, 1195, 1537, 1409, 858, 1971, 2214, 1311, 1326, 1383, 1231, 1141]
我想从大约2462
的第一组峰中选出1037, 2279, 2462, 2193
,然后继续从2456
的下一组峰中选出506, 2411, 2456, 2295, 915
。分组的位置未知,这是找到它们并从每个分组中选择一个最高编号的问题。
这是我目前拥有的功能,但它不能100%工作,并且不适用于某些数组。
let currHigh = 0, store = [], limit = 2100;
for (let s = 0; s < arr.length; s++) {
if (arr[s] > limit && currHigh === 0) {
currHigh = arr[s]
} else if (arr[s] > limit && arr[s] > currHigh) {
currHigh = arr[s];
} else if (arr[s] < currHigh) {
if (arr[s] < limit) {
store.push(currHigh); currHigh = 0;
}
}
}
console.log(store)
最高点总是非常相似(2000多个),数字组的位置相似但不相同,所以我不能真正依靠它。
因此,第一个数组和预期/期望的输出将是:
const arr = [939, 1301, 253, 1380, 1037, 2279, 2462, 2193, 2121, 1424, 506, 2411, 2456, 2295, 915, 1276, 1532, 1359, 985, 2182, 2407, 2103, 2392, 2294, 765, 1195, 1537, 1409, 858, 1971, 2214, 1311, 1326, 1383, 1231, 1141]
Outputted Peaks: [2462, 2456, 2407, 2294, 2214]
另一个带有预期/预期输出的示例数组:
const arr = [1365, 1324, 1013, 1220, 1259, 2204, 2212, 1938, 1882, 1545, 1236, 2090, 2614, 1949, 1307, 1628, 1780, 1263, 1184, 2184, 1411, 1306, 2010, 2057, 1339, 1624, 2480, 2575, 2425, 2617, 2479, 1929, 1805, 1869, 1341, 1104, 2195, 1661, 1174, 1447, 1761, 1362, 1430]
Outputted Peaks: [2212, 2614, 2184, 2480, 2617, 2195]
编辑:为避免引起混淆,请想象一下,如果要采用给定数组中的值并将其绘制在图形上,则图形中将有几个峰相互隔开。我需要一个能够获得这些峰值的功能。查找组只是查找峰的一种方法。他们就像迷你山脉。因此,例如,您不想获得位于“山顶”的高编号。
编辑:附加图像以解释峰。紧接另一个高编号的高编号不是峰值,只有一小部分相邻编号中的最高编号是峰值。
最终编辑:此图最能说明这一点,因为很难想象仅查看数组的图:
https://jsbin.com/nicuciquru/1/edit?js,output
所以我在这里需要的是峰[1301, 1380, 2462, 2456, 1532, 2407, 2492, 1537, 2214, 1383]
,您可以在图表上看到它们。然后可以从那里轻松地用阈值过滤这些峰,例如消除2000以下的任何峰。
答案 0 :(得分:1)
这是一个在样品阵列中找到所有峰的函数:
const chart = [939, 1301, 253, 1380, 1037, 2279, 2462, 2193, 2121, 1424, 506, 2411, 2456, 2295, 915, 1276, 1532, 1359, 985, 2182, 2407, 2103, 2392, 2294, 765, 1195, 1537, 1409, 858, 1971, 2214, 1311, 1326, 1383, 1231, 1141]
const findPeaks = chart => chart.reduce((agg, current, i) => {
const prev = chart[i - 1];
const next = chart[i + 1];
return current > prev && current > next ? [...agg, current] : agg;
}, []);
const peaks = findPeaks(chart);
console.log('peaks', peaks);
此日志:[1301, 1380, 2462, 2456, 1532, 2407, 2392, 1537, 2214, 1383]
这与您的问题的预期输出不符,但确实给出了“什么是峰值”的准确答案。
在这种情况下,“峰值”定义为前任和后任均低于其自身的任何数字。即[1,100,1]得出100。[1,2,3,100,3,2,100,1]得到[100,100]
更新
根据您的反馈,这是一个函数,要求一个峰值在每个侧具有2的距离。结果仍然与您的问题不同,但这符合新表达的标准:
const findPeaks = chart => chart.reduce((agg, current, i) => {
const twoBack = chart[i - 2];
const prev = chart[i - 1];
const next = chart[i + 1];
const twoForward = chart[i + 2];
return (twoBack < prev && prev < current) && (current > next && next > twoForward )
? [...agg, current]
: agg;
}, []);
对于上述输入,将产生:
[2462, 2456, 1532, 1537, 1383]
更新2
这是查找 all 峰,计算出中位数并返回大于中位数的所有峰的代码版本。这是与您在问题中要求的最接近的结果:
const findPeaks = chart => {
const peaks = chart.reduce((agg, current, i) => {
const twoBack = chart[i - 2];
const prev = chart[i - 1];
const next = chart[i + 1];
const twoForward = chart[i + 2];
return (prev < current) && (current > next)
? [...agg, current]
: agg;
}, []);
const mean = peaks.reduce((a, b) => a + b) / peaks.length;
return peaks.filter(peak => peak > mean);
}
此输出为:
[2462, 2456, 2407, 2392, 2214]
答案 1 :(得分:0)
没有更精确地定义所需的输出(例如,什么是组?),这是一种简单的算法:
1)将数组拆分为“低”和“高”序列。
[1, 10000, 100, 101, 20000, 20050, 30, 10, 2]
=> [1], [10000], [100, 101], [20000, 20050], [30, 10, 2]
。2)返回每个高位序列的最大值。
let peaks = arr => {
let isHigh = a => a >= 2000;
let isLow = a => !isHigh(a);
let groups = [];
while (arr.length && arr.some(isHigh)) {
arr.splice(0, arr.findIndex(isHigh));
groups.push(arr.splice(0, arr.findIndex(isLow)));
}
return groups.map(group => Math.max(...group));
};
const arr = [939, 1301, 253, 1380, 1037, 2279, 2462, 2193, 2121, 1424, 506, 2411, 2456, 2295, 915, 1276, 1532, 1359, 985, 2182, 2407, 2103, 2392, 2294, 765, 1195, 1537, 1409, 858, 1971, 2214, 1311, 1326, 1383, 1231, 1141];
console.log(peaks(arr));
const arr2 = [1365, 1324, 1013, 1220, 1259, 2204, 2212, 1938, 1882, 1545, 1236, 2090, 2614, 1949, 1307, 1628, 1780, 1263, 1184, 2184, 1411, 1306, 2010, 2057, 1339, 1624, 2480, 2575, 2425, 2617, 2479, 1929, 1805, 1869, 1341, 1104, 2195, 1661, 1174, 1447, 1761, 1362, 1430];
console.log(peaks(arr2));
答案 2 :(得分:0)
根据我们讨论的所有内容,我从您的评论中看到,我认为以下内容应该为您解决。基本上只是迭代这些点并检查当前点是否大于上一个点和下一个点-我们可以将这些点视为“峰值”:
function getPeaks(points) {
let prev;
let next;
return points.filter((curr, idx, arr) => {
if (idx > 0) {
prev = arr[idx - 1];
}
if (idx < (arr.length - 1)) {
next = arr[idx + 1];
}
if (prev) {
if (prev > curr) {
return false;
}
}
if (next) {
if (next > curr) {
return false;
}
}
return true;
});
}
const points = [939, 1301, 253, 1380, 1037, 2279, 2462, 2193, 2121, 1424, 506, 2411, 2456, 2295, 915, 1276, 1532, 1359, 985, 2182, 2407, 2103, 2392, 2294, 765, 1195, 1537, 1409, 858, 1971, 2214, 1311, 1326, 1383, 1231, 1141];
console.log(getPeaks(points));
我将得到的数组与Randy的图表进行了比较,数据似乎符合预期。
答案 3 :(得分:0)
为什么不保持简单?
var arr = [1,6,4,3,9,11];
var peaks = arr.sort((a, b) => a - b).reverse();
输出为: [11,9,6,4,3,1]
然后:
var top5 = peaks.slice(0,5);
,结果是: [11,9,6,4,3]
或您的数学家的完整代码:
const peaks1 = [939, 1301, 253, 1380, 1037, 2279, 2462, 2193, 2121, 1424, 506, 2411, 2456, 2295, 915, 1276, 1532, 1359, 985, 2182, 2407, 2103, 2392, 2294, 765, 1195, 1537, 1409, 858, 1971, 2214, 1311, 1326, 1383, 1231, 1141];
const peaks2 = [1365, 1324, 1013, 1220, 1259, 2204, 2212, 1938, 1882, 1545, 1236, 2090, 2614, 1949, 1307, 1628, 1780, 1263, 1184, 2184, 1411, 1306, 2010, 2057, 1339, 1624, 2480, 2575, 2425, 2617, 2479, 1929, 1805, 1869, 1341, 1104, 2195, 1661, 1174, 1447, 1761, 1362, 1430];
const peaks = [peaks1, peaks2];
function getPeaks(arr){
let peaks = [];
for(let i=0;i<arr.length;i++){
let currPeak = arr[i].sort((a, b) => a - b).reverse().slice(0,1)[0];
peaks.push(currPeak);
}
return peaks.sort((a, b) => a - b).reverse();
}
let result = getPeaks(peaks);
,结果应该是: [2617,2462]
答案 4 :(得分:0)
以下解决方案的运行时间为 O(n):
// steps
// loop through array
// on each element
// if element is greater than the element on left
// take note of index
// if element is greater than element on right
// and pos is not default value
// add pos to positions and add value to peaks
function pickPeaks(arr) {
// assign pos to default value
let pos = -1
// create output which will be returned later
const result = { pos: [], peaks: [] }
// loop through array
for (let index = 1; index < arr.length; index += 1) {
let left = arr[index - 1]
let element = arr[index]
// on each element
// if element is greater than the element on left
if (element > left) {
// take note of index
pos = index
}
// if element is greater than element on right
// and pos is not default value
if (left > element && pos != -1) {
// add pos to positions and add value to peaks
result['peaks'].push(arr[pos])
result['pos'].push(pos)
// reset pos
pos = -1
}
}
// return result
return result['peaks']
}