43

I get an Array with an unknown Number of data. But I only have an predefined amount of data to be shown/store. How can I take every nth Element of the initial Array and reduce it in JavaScript?

Eg.: I get an Array with size=10000, but are only able to show n=2k Elements.

I tried it like that: delta= Math.round(10*n/size)/10 = 0.2 -> take every 5th Element of the initial Array.

for (i = 0; i < oldArr.length; i++) {
  arr[i] = oldArr[i].filter(function (value, index, ar) {
    if (index % delta != 0) return false;
    return true;
  });
}

With 0.2 it´s always 0, but with some other deltas (0.3) it is working. Same for delta=0.4, i works, but every second Element is taken with that. What can I do to get this to work?

6
  • What is n? What is k? What is delta? What is oldArr? Commented Nov 2, 2015 at 16:57
  • How about delta = size / n? Commented Nov 2, 2015 at 16:58
  • 1
    0.2 evenly divides all the integers, so someInt % 0.2 == 0 always. I think you want someInt % (1 / 0.2), ie someInt % 5 Commented Nov 2, 2015 at 17:01
  • 1
    @James 1 % 0.2 produces 0.19999999999999996 for me, because floating point math is broken Commented Nov 2, 2015 at 17:06
  • @Oriol you're right! 1 % 0.25 works (because 0.25 can be exactly represented in binary, I suppose), I guess using modulus operator on non-integer operands is a bad idea in JS. Commented Nov 2, 2015 at 17:10

7 Answers 7

64

Maybe one solution :

avoid filter because you don't want to loop over 10 000 elements ! just access them directly with a for loop !

 
var log = function(val){document.body.innerHTML+='<div></pre>'+val+'</pre></div>'} 

var oldArr = [0,1,2,3,4,5,6,7,8,9,10]
var arr = [];

var maxVal = 5;

var delta = Math.floor( oldArr.length / maxVal );

// avoid filter because you don't want
// to loop over 10000 elements !
// just access them directly with a for loop !
//                                 |
//                                 V
for (i = 0; i < oldArr.length; i=i+delta) {
  arr.push(oldArr[i]);
}


log('delta : ' + delta + ' length = ' + oldArr.length) ;
log(arr);

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks, I guess that´s it. Especially since that should be faster than with the modulo-check. And I don´´t have 10k Elements. It´s an 2D-Array, so in the other Version there would even be 100k checks.
33

Filter itself returns an array. If I'm understanding you correctly, you don't need that surrounding loop. So:

newArr = oldArr.filter(function(value, index, Arr) {
    return index % 3 == 0;
});

will set newArr to every third value in oldArr.

Comments

12

Try

arr = oldArr.filter(function (value, index, ar) {
    return (index % ratio == 0);
} );

where ratio is 2 if you want arr to be 1/2 of oldArr, 3 if you want it to be 1/3 of oldArr and so on.

ratio = Math.ceil(oldArr.length / size); // size in the new `arr` size

You were calling filter() on each element of oldAdd inside a loop and you're supposed to call filter() on the whole array to get a new filtered array back.

1 Comment

Shouldn't it be Math.ceil() to prevent the new array from being larger than the desired size?
1

this also works by using map to create the new array without iterating over all elements in the old array..

// create array with 10k entries
const oldArr = [ ...Array( 10000 ) ].map( ( _el, i ) => i );
const max = 10;
const delta = Math.floor( oldArr.length / max );

const newArr = [ ...Array( max ) ].map( ( _el, i ) => (
  oldArr[ i * delta ]
) );

console.log( newArr );

Comments

0

Borrowing from @anonomyous0day's solution, generate a new Array with the desired indices from the given array:

(Take every 3 items)

Array.prototype.take = function(n) {
  if (!Number(n) && n !== 0) {
    throw new TypeError(`Array.take requires passing in a number.  Passed in ${typeof n}`);
  } else if (n <= 0) {
    throw new RangeError(`Array.take requires a number greater than 0.  Passed in ${n}`);
  }

  const selectedIndicesLength = Math.floor(this.length / n);
  return [...Array(selectedIndicesLength)].map((item, index) => this[index * n + 1]);
};

[1, 2, 3, 4, 5, 6, 7, 8].take(2); // => 2, 4, 6, 8

Comments

0

may help!

 const myFunction = (a, n) => {

   let array = []


    for(i = n; i <= a.length; i += n){
      array.push(a[i-1]);

   }

  return array;

}

Comments

0

To separate array every 5 element need to make another 2d array to store every 5 element separately it's my solution if can help to your problem

const arrayParts = [];
var separateEach = 5;
var startLen = 0;

var partCount = Math.ceil(infos.length / separateEach);
console.log('partCount', partCount);

for (var i = 1; i <= partCount; i++) {
  arrayParts.push(infos.slice(startLen, separateEach * i));
  startLen = separateEach * i;
}

console.log('Parts ', arrayParts);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.