Javascript从数组中的高位组中挑选峰值

时间:2019-06-13 15:44:45

标签: javascript arrays filter

很难用标题来描述它,但是从这里的描述和代码中应该很清楚。我正在尝试从一组峰中选择一个数组中最高的数字,然后转到下一组并从下一组高点中获取下一个峰数。

例如在此数组中:

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]

编辑:为避免引起混淆,请想象一下,如果要采用给定数组中的值并将其绘制在图形上,则图形中将有几个峰相互隔开。我需要一个能够获得这些峰值的功能。查找组只是查找峰的一种方法。他们就像迷你山脉。因此,例如,您不想获得位于“山顶”的高编号。

编辑:附加图像以解释峰。紧接另一个高编号的高编号不是峰值,只有一小部分相邻编号中的最高编号是峰值。 enter image description here

最终编辑:此图最能说明这一点,因为很难想象仅查看数组的图:

https://jsbin.com/nicuciquru/1/edit?js,output

所以我在这里需要的是峰[1301, 1380, 2462, 2456, 1532, 2407, 2492, 1537, 2214, 1383],您可以在图表上看到它们。然后可以从那里轻松地用阈值过滤这些峰,例如消除2000以下的任何峰。

5 个答案:

答案 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']
}