最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Return index of nearest values in an array - Stack Overflow

programmeradmin0浏览0评论

I have this:

var scores=[0.7, 1.05, 0.81, 0.96, 3.2, 1.23];

What's the more readable way to return the indexes of the nearest values to another variable?

For instance:

With variable = 1 Should return { low: 3, high: 1 }

I have this:

var scores=[0.7, 1.05, 0.81, 0.96, 3.2, 1.23];

What's the more readable way to return the indexes of the nearest values to another variable?

For instance:

With variable = 1 Should return { low: 3, high: 1 }

Share Improve this question edited Sep 19, 2014 at 14:58 rnrneverdies asked Sep 15, 2014 at 18:11 rnrneverdiesrnrneverdies 15.7k9 gold badges66 silver badges95 bronze badges 2
  • 6 Iterate over the array, pare values and record indices? If by "best" you mean something more elaborated, maybe build an interval tree? en.wikipedia/wiki/Interval_tree – Felix Kling Commented Sep 15, 2014 at 18:13
  • less elaborate, but simple. i was trying Array.reduce returning an object but could not. – rnrneverdies Commented Sep 15, 2014 at 18:21
Add a ment  | 

7 Answers 7

Reset to default 5

Almost as simple but faster (O(n)) than sort:

const nearest = (arr, n) => arr.reduce((r, x) => ({
  lo: ((x < n) && (x > r.lo) ? x : r.lo),
  hi: ((x > n) && (x < r.hi) ? x : r.hi)
}), { lo: -Infinity, hi: Infinity })

const mapIndexOf = (obj, lookup) => Object.keys(obj).reduce(
  (a, v) => ({ ...a, [v]: lookup.indexOf(obj[v]) }), {}
) 

const scores = [0.7, 1.05, 0.81, 0.96, 3.2, 1.23]

console.log(mapIndexOf(nearest(scores, 1), scores))

Slow (O(n*log(n)) and simple:

const nearest = (arr, val) => (sorted => (indexOfVal => ({
  lo: sorted[indexOfVal - 1],
  hi: sorted[indexOfVal + 1]
}))(sorted.indexOf(val)))([...arr, val].sort())


const mapIndexOf = (obj, lookup) => Object.keys(obj).reduce(
  (a, v) => ({ ...a, [v]: lookup.indexOf(obj[v]) }), {}
) 

const scores = [0.7, 1.05, 0.81, 0.96, 3.2, 1.23]

console.log(mapIndexOf(nearest(scores, 1), scores))

This way:

var lower = function(a,b){return a.element > b.element ? b : a; };
var higher = function(a,b){return a.element > b.element ? a : b; };
var withIndex = function(element,index){ return {element: element, index: index}; };
var nearest = function(array, limit) {
  var lowerValues = array.map(withIndex).filter(function(a){ return a.element<limit });
  var higherValues = array.map(withIndex).filter(function(a){ return a.element>limit });
  return {
    low: lowerValues.reduce(higher).index, 
    high: higherValues.reduce(lower).index
  };
}
var scores=[0.7, 1.05, 0.81, 0.96, 3.2, 1.23];
var lowIndex = 0;
var highIndex = 0;
var currentLow = 0;
var currentHigh = 0;
var temp = 0;
var variable = 2;
for(var i = 0; i < scores.length; i++)
{
    temp = variable - scores[i];
    if((currentLow == 0) && (temp > 0))
    {
        currentLow = temp;
    }
    if((currentHigh == 0) && (temp < 0))
    {
        currentHigh = temp;
    }
   if((temp >= currentHigh) && (temp <= 0))
   {
      highIndex = i;
      currentHigh = temp;
   }
   if((temp <= currentLow) && (temp >= 0))
   {
      lowIndex = i;
      currentLow = temp;
   }
}
window.alert("Low:" + lowIndex + "  High:" + highIndex);

This code works and you can see the logic of whats going on.

Loop over the array, subtract the value from your variable, pare, then record the closest values. Here's a quick example:

var value = 1;
var scores = [0.7, 1.05, 0.81, 0.96, 3.2, 1.23];
var ret = {};

for(var i = 0, len = scores.length; i < len; i++){
  var p = scores[i] - value;
  if(p > 0){
    if(!ret.high){
      ret.high = i;
    }
    else if(scores[i] < scores[ret.high]){
      ret.high = i;
    }
  }
  else if(p < 0){
    if(!ret.low){
      ret.low = i;
    }
    else if(scores[i] > scores[ret.low]){
      ret.low = i;
    }
  }
  else{
    ret = {
      low: i,
      high: i
    };
    break;
  }
}

document.getElementById('result').innerHTML = 'high: '+ret.high+' low: '+ret.low;
<div id="result"></div>

// for storing greater values and their indeces   
var gtVals = {
    val : [],
    ind : []
};

// for storing lesser values and their indeces 
var ltVals = {
    val : [],
    ind : []
} 

var scores=[0.7, 1.05, 0.81, 0.96, 3.2, 1.23];

function highLow(value){
     var val = parseFloat(value);

         for(var i = 0; i < scores.length ; i++){
            if(scores[i] > val ){
                gtVals.val.push(scores [i] - val );
                gtVals.ind.push(i );
           }
        else{
             ltVals.val.push(val - scores[i] );
             ltVals.ind.push(i );
         }

     }
    var higherindex = gtVals.ind[gtVals.val.indexOf((Math.min.apply(Math, gtVals.val)))];
    var lowerindex = ltVals.ind[ltVals.val.indexOf((Math.min.apply(Math, ltVals.val)))];
    return {
        low: lowerindex,
        high :  higherindex
    };
}

console.log(highLow(1));

http://jsfiddle/2q572hxj/3/

For people who love perl, assembler or regular expressions, here a solution near to a single-liner:

var pV = 1;
var scores=[0.7, 1.05, 0.81, 0.96, 3.2, 1.23];

for(var h=0,l=0,i=0,tmp=0,lV=Number.MAX_VALUE,hV=lV; i < scores.length; i++) {
   tmp=pV-scores[i];tmp>0 && tmp<lV ? (l=i,lV=tmp) : tmp<0 && -tmp<hV ? (h=i,hV=-tmp) : 0; }

l (lowercase "L") holds the index of the lowest value, h (lowercase "H") holds the index of the highest value. Have fun :)

发布评论

评论列表(0)

  1. 暂无评论