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

How to group the "closest" numbers in an array using javascript - Stack Overflow

programmeradmin6浏览0评论

I have an array of numbers sorted in ascending order. How to group the "closest" numbers (where the difference between the numbers is less than 5, for example)? So out of [1, 4, 5, 23, 40, 55, 56, 100, 234] I want to get [[1, 4, 5], 23, 40, [55, 56], 100, 234]

I have an array of numbers sorted in ascending order. How to group the "closest" numbers (where the difference between the numbers is less than 5, for example)? So out of [1, 4, 5, 23, 40, 55, 56, 100, 234] I want to get [[1, 4, 5], 23, 40, [55, 56], 100, 234]

Share Improve this question asked Jan 18, 2017 at 16:41 ZhurovichZhurovich 755 bronze badges 1
  • 1 you need to show some effort into solving the problem, paste your code so far if you have any – Brian Commented Jan 18, 2017 at 16:44
Add a ment  | 

5 Answers 5

Reset to default 7

You could check the predecessor and if in range add to array.

var data = [1, 4, 5, 23, 40, 55, 56, 100, 234],
    result = data.reduce(function (r, a, i, aa) {
        if (a - aa[i - 1] < 5) {
            if (!Array.isArray(r[r.length - 1])) {
                r[r.length - 1] = [r[r.length - 1]];
            }
            r[r.length - 1].push(a);
            return r;
        }
        r.push(a);
        return r;
    }, []);

console.log(result); // [[1, 4, 5], 23, 40, [55, 56], 100, 234]

Use Array#reduce method with an empty array as the initial value where update the array by checking the last element.

var data = [1, 4, 5, 23, 40, 55, 56, 100, 234];

var res = data.reduce(function(arr, e) {
  // cache last element index
  var i = arr.length - 1;
  // check array exist atleast one element
  if (i > -1) {
    // check last element is array
    if (Array.isArray(arr[i])) {
      // pare last element in array and current element is adjacent
      // if yes push into that array otherwise push into main array
      e - arr[i][arr[i].length - 1] < 5 ? arr[i].push(e) : arr.push(e);
      // if last element is not an array
    } else {
      // if last element and current element is adjacent
      // update last element with an array or just push as usual
      e - arr[i] < 5 ? arr[i] = [arr[i], e] : arr.push(e);
    }
    // if array is empty
  } else
  // simply push the element
    arr.push(e);
  // retuen the array reference
  return arr;
  // set initial value as an epty array
}, [])

console.log(res);

What about another (may shorter)reduce:

 newarray=array.reduce((newarray,number)=>{
   var last=newarray.pop()||[];
      if(last.every(elem=>elem+6>number)){
       last.push(number);
       newarray.push(last);
       return newarray;
      }
       newarray.push(last);
       newarray.push([number]);
       return newarray;
      },[]);

You can use reduce and check last element added to add to last array or insert new one, and when you get to last element of data you use map to remove arrays with one element.

var data = [1, 4, 5, 23, 40, 55, 56, 100, 234];

var result = data.reduce(function(r, e, i) {
  if (i != 0) {
    (e - data[i - 1] < 5) ? r[r.length - 1].push(e): r.push([e])
  } else {
    r.push([e])
  }
  if (i == data.length - 1) r = r.map(e => e.length == 1 ? e[0] : e)
  return r;
}, [])

console.log(result)

This is a good question...

Though my answer is slightly convoluted, for experimental purposes you can also do like this...

var data = [1, 4, 5, 23, 40, 55, 56, 100, 234],
  result = data.reduce((p,c) => p.length ? p[p.length-1].length ? c-p[p.length-1][p[p.length-1].length-1] < 5 ? (p[p.length-1].push(c),p)
                                                                                                              : (p.push(c),p)
                                                                : c-p[p.length-1] < 5 ? (p[p.length-1] = [p[p.length-1],c],p)
                                                                                      : (p.push(c),p)
                                         : c-p < 5 ? [[p].concat(c)]
                                                   : [p,c]);
console.log(JSON.stringify(result));

I think it's pretty efficient too.

Ok so let's try something funny... We will feed this algorithm with an array of 1,000,000 random items among 1 ~ 5,000,000 in sorted order and measure how long it takes to group them for a diff < 5.

var data = Array(1000000).fill()
                         .map(_ => ~~(Math.random()*5000000)+1)
                         .sort((a,b) => a-b),
  result = [];
console.time("grouping");
  result = data.reduce((p,c) => p.length ? p[p.length-1].length ? c-p[p.length-1][p[p.length-1].length-1] < 5 ? (p[p.length-1].push(c),p)
                                                                                                              : (p.push(c),p)
                                                                : c-p[p.length-1] < 5 ? (p[p.length-1] = [p[p.length-1],c],p)
                                                                                      : (p.push(c),p)
                                         : c-p < 5 ? [[p].concat(c)]
                                                   : [p,c]);
console.timeEnd("grouping");
console.log(result.length);

Like ~200ms in average. Seems cool..!

发布评论

评论列表(0)

  1. 暂无评论