Javascript: take every nth Element of Array - javascript

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?

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);

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.

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.

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

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 );

may help!
const myFunction = (a, n) => {
let array = []
for(i = n; i <= a.length; i += n){
array.push(a[i-1]);
}
return array;
}

Related

sample array n^2 times without the same number occurring twice in a row and not repeating every n

I'm trying to write a function that has the arguments of the array to sample arr and the number of samples, size (which is sqaured) and randomly samples from the original array:
arr = [1,2,3,4]
single_number = (x) => {
return x[Math.floor(Math.random()*x.length)];
}
randomize = (arr, size) => {
return Array(size*size).fill().map(x => single_number(arr))
}
randomize(arr, 5)
I want to add the additional requirements to my randomize function:
no number shows up twice in a row
make sure every sizeth item is not the same as the one before it
For example
randomize([1,2,3,4], 2)
[2,4,3,2,4,1,1,2,2,1,4,1,1,1,3,1,1,4,4,1,3,3,2,2,3]
CASE (1)
[
2,4,3,2,4,
2,1,
2,2, // illegal!
1,4,
1,1,1, // illegal!
3,
1,1, // illegal!
4,4, // illegal!
1,
3,3, // illegal!
2,2, // illegal!
3
]
CASE (2)
[
2,4,3,2,4, [0] === 2
2,1,2,2,1, [5] === 2 // illegal!
4,1,1,1,3,
1,1,4,4,1,
3,3,2,2,3
]
I'm trying to use functional programming and avoid a for loop if possible since I think I can do this with a nested for loop?
Well, this isn't as pretty as one would hope, but I think it accomplishes the objective: Iterate size^2 times and choose random elements from the input, taking care to exclude the last value and last nth value chosen...
const randomize = (array, size) => {
const rand = () => Math.floor(Math.random() * array.length);
const randExcept = exclude => {
let v = array[rand()];
while (exclude.includes(v)) v = array[rand()];
return v;
}
const indexes = Array.from(Array(size*size).keys());
let lastV = null, nthV = null;
return indexes.map(i => {
let exclude = nthV!==null && i%size===1 ? [lastV, nthV] : [lastV];
let v = randExcept(exclude);
lastV = v;
if (i%size===1) nthV = v;
return v;
})
}
console.log( JSON.stringify(randomize([1,2,3,4], 2)) )
This defines nth values by the count into the array, so for size===2, the constraint is that every second element (indexes 1,3,5...) can't be equal to the prior second element.
I'd probably do something like this:
const values = [1,2,3,4]
function randomize(values, size) {
let prev;
let prevNth;
return Array(size*size).fill().map( randomNumber );
function randomNumber(_,i) {
let value, ok;
do {
value = values[ Math.floor( Math.random() * values.length ) ];
ok = value != prev;
if ( i % size === 0) {
ok = ok && value != prevNth;
prevNth = value;
}
prev = value;
} while (!ok);
return value;
}
}
arr = randomize(values, 5)
console.log(JSON.stringify(arr));
Or this, using a generator to generate the appropriately sized stream of randomness:
const values = [1,2,3,4];
const arr1 = Array.from( randomValues(5,values) );
console.log(JSON.stringify(arr1));
function *randomValues(n, values) {
const limit = n*n;
let prev, prevNth;
for ( let i = 0 ; i < limit ; ++i ) {
const isNthValue = i % n === 0;
const value = randomValue( values, prev, isNthValue ? prevNth : undefined );
yield value;
prev = value;
prevNth = isNthValue ? value : prevNth;
}
}
function randomValue(values, test1, test2 ) {
let value;
do {
value = values[ Math.floor( Math.random() * values.length ) ];
} while (value === test1 || value === test2 );
return value;
}

How do I find two numbers in an array that are equal to a target number

I'm looking to find two numbers in an array that are equal to a particular target number. I thought this would be a simple task using .filter but for some reason my code only works when I'm looking for a target number of 4 but doesn't work for anything else?
What am I missing here?
var numbers2 = [1,2,3,4];
var target = 3;
var found = numbers2.filter((num) => {
return (num + num) !== target;
});
console returns (4) [1,2,3,4] as opposed to 2[1,2].
var numbers = [1,4,3,2,6,8,12,1,1,1,2,3,4];
var target = 3;
var output = [];
// Use a set to remove duplicate numbers
numbers = [...new Set(numbers)]; // Only do this step if you dont want duplicates ( like 2+2 = 4 so if your target was for 2, would not show up in the list )
// Sort the numbers from lowest to highest
numbers.sort( (a,b) =>a-b);
// Get index of first number that matches the target or is greater than the target
let index;
for( let i =0; i < numbers.length; i++) {
if( numbers[i] >= target ) {
index = i;
break;
}
}
// Remove all numbers from the array starting at the previous index as these are not possible to add up with another number to the target
if( index ) {
numbers.splice(index, numbers.length - index );
}
// Loop through the remianing array to get first number
numbers.forEach( ( num1, index1) => {
// Loop through array again to get second number
numbers.forEach( (num2, index2) => {
// Check if number is same is same index as you dont want to add the same value to itself, then check if the 2 numbers equal the target number
if( index1 !== index2 && num1 + num2 === target ) {
// If number already exists in array dont duplicate otherwise add it to the array
if( output.indexOf( num1 ) == -1 ) {
output.push( num1);
}
// If number already exists in array dont duplicate otherwise add it to the array
if( output.indexOf( num2 ) == -1 ) {
output.push( num2);
}
}
});
});
console.log( output);
You could find the array location of your target number through using a array.forEach, array.indexOf(), array.find(), and array.findIndex():
let numbers2 = [1,2,3,4];
let target = 4;
//Using foreach
numbers2.forEach((item, index)=>{
if (item == target){
console.log("Found the target at array location "+index);
}
});
//Or through using indexOf():
console.log("Found the target at array location "+numbers2.indexOf(target));
//Or through using find():
const found = numbers2.find(element => element == target);
console.log("Found "+target+" in the array.");
//Or through findIndex():
const target1 = (a) => a == target;
console.log("Found the target at array location "+numbers2.findIndex(target1));
Assuming:
you only need one pair
[2,2] does not count when your target is 4 (as '2' only appears once in the array)
One way to go is:
let numbers = [1, 2, 3, 4]
let target = 4;
let output = [];
const N = numbers.length
outer: for (let i = 0; i < N; i++) {
for (let j = i + 1; j < N; j++) {
if (numbers[i] + numbers[j] === target) {
output.push(numbers[i], numbers[j])
break outer;
}
}
}
console.log(output); //[1,3]
Edit: even if you want more than one pair, it's easy to modify to get that effect (now the target is 5):
let numbers = [1, 2, 3, 4]
let target = 5;
let output = [];
const N = numbers.length
for (let i = 0; i < N; i++) {
for (let j = i + 1; j < N; j++) {
if (numbers[i] + numbers[j] === target) {
output.push([numbers[i], numbers[j]])
}
}
}
console.log(output); //[[1,4], [2,3]]
This is an ideal case for the humble for loop. Methods like .forEach() will always try to loop over all the elements in an array, but if we order the data before we start the search we can break early and eliminate a lot of searching.
Ergo...
var numbers = [1,2,3,4];
var target = 5;
var output = [];
// Handling ordered data is much faster than random data so we'll do this first
numbers.sort();
// We want to start the inner search part way up the array, and we also want
// the option to break so use conventional for loops.
for (let i = 0; i<numbers.length; i++) {
for (let j=i+1; j<numbers.length;j++) {
// If the total = target, store the numbers and break the inner loop since later numbers
// will all be too large
if ((numbers[i]+numbers[j])===target) {
output.push([numbers[i], numbers[j]]);
break;
}
}
// Stop searching the first loop once we reach halfway, since any subsequent result
// will already have been found.
if (numbers[i]>(target/2)) {
break;
}
}
console.log( output);
It makes very little sense to get an array of single numbers, because you'll get all the numbers except for the last one unless the array starts at zero or there are numbers skipped. So I've written a function that'll return an array of single numbers or an array of expressions (strings).
First, make a copy of the array:
const array = [1, 2, 3, 4]
const copy = array.slice(0);
Next, use .flatMap() for the first set of iterations:
array.flatMap(num => { // This is the outer loop of numbers
If the third parameter expression is undefined it will default to false. Then .filter() the copy array, the criteria being that the number from the outer loop plus the current number of the inner loop equals the target number AND the numbers cannot be identical.
copy.filter(n => n !== num && target === n + num);
/*
Iterations on the first iteration of outer loop
1 + 1, 1 + 2, 1 + 3,...
*/
If expression is true, then use .flatMap() to return an expression (string) of whatever equals the target number or an empty array (which returns as nothing since .flatMap() flattens it's returns by a level). If both numbers are identical an empty array will be returned.
copy.flatMap(n => n === num ? [] :
target === n + num ? `${n} + ${num}` :
[]
);
If expression is true half of the array is returned so that there isn't any reversed dupes (ex. 6+2 and 2+6)
let half = result.length / 2;
result = result.slice(0, half);
const log = data => console.log(JSON.stringify(data));
// [1, 2, 3,...10]
const array10 = [...new Array(10)].map((_, i) => i + 1);
// [0, 2, 4, 6,...18]
const arrayEven = [...new Array(10)].map((_, i) => i * 2);
function operands(array, target, expression = false) {
const copy = array.slice(0);
let result = array.flatMap(num => {
if (expression) {
return copy.flatMap((n, i) =>
num === n ? [] :
target === n + num ? `${n} + ${num}` :
[]
);
}
return copy.filter(n => n !== num && target === n + num);
});
if (expression) {
let half = result.length / 2;
result = result.slice(0, half);
}
return result;
}
// Return as an array of single numbers
log(array10);
log('3: '+operands(array10, 3));
log('8: '+operands(array10, 8));
log('5: '+operands(array10, 5));
log(arrayEven);
log('2: '+operands(arrayEven, 2));
log('8: '+operands(arrayEven, 8));
log('15: '+operands(arrayEven, 15));
log('=======================');
// Return as an array of expressions (string)
log(array10);
log('3: '+operands(array10, 3, true));
log('8: '+operands(array10, 8, true));
log('5: '+operands(array10, 5, true));
log(arrayEven);
log('2: '+operands(arrayEven, 2, true));
log('8: '+operands(arrayEven, 8, true));
log('15: '+operands(arrayEven, 15, true));

How to populate an array with integers

Please, how do you populate an array say ‘num’ with numbers not in a second array say ‘fig’? I’m trying to use a loop to have the values of the already populated array ‘fig’ compared to ‘num’ which is to be populated with integers not found in ‘fig’. I’m a bit confused.
If you need to do an array with n numbers you can use this two ways.
const arrayLength = 100;
const numberArray = [...new Array(arrayLength).keys()]
const anotherWay = new Array(arrayLength).fill().map((_, idx) => idx + 1);
console.log(numberArray, anotherWay)
so to do this we have to do a few things:
1) define an existing array with numbers to avoid
2) define length on new array
3) generate a random number and make it an integer
4) check to see if we need to avoid
5) if it's a new value add it to the second array
var first=[55,45,35,1,2,3,4,5];
var second = [];
var i = 7;
var x;
while (i != 0){
x = ~~(Math.random()*100);
var check = false;
for(let j=0; j<first.length;j++){
if(x == first[j]){
check = true;
}
}
if(!check){
second.push(x);
i--;
}
}
console.log(second);
const fig = [-21, 0, 3, 6, 7, 42]
const min = Math.min(...fig) // or fig[0] if the the array is already sorted
const max = Math.max(...fig) // or fig[fig.length - 1]
const num = Array.from({ length: max - min }, (_, i) => i + min)
.filter(el => !fig.includes(el))
or, saving one loop
const num = Array.from({ length: max - min }).reduce((acc, _, i) => {
const curr = i + min
if (!fig.includes(curr)) {
return acc.concat(curr)
}
return acc
}, [])
This is assuming your range is from the smallest number in fig to the largest in fig.

Drop last element of javascript array when array reaches specific length

I would like to cache some data in javascript, but the cache should be limited to 10 elements for example.
I can place the objects in javascript array, but what is the best way to keep the array limited to 10 elements?
Example:
function getData(dataId) { return new NextDataObject(dataId); }
var array = new Array();
array.push(getData(0));
array.push(getData(1));
(...)
array.push(getData(10)); // this should result in dropping "oldest" data, so getData(0) should be removed from the array, so that in array there are only 10 objects at maximum
Should such mechanism be written manually (using splice() for example?) or are there better ways to achieve such "cache" structure in javascript?
BTW: in this particular situation I'm using angular.
Override the push function of your caching array.
var array = new Array()
array.push = function (){
if (this.length >= 10) {
this.shift();
}
return Array.prototype.push.apply(this,arguments);
}
Plunker
To make this more reusable I created a method which returns new instance of such array (basing on above code).
function getArrayWithLimitedLength(length) {
var array = new Array();
array.push = function () {
if (this.length >= length) {
this.shift();
}
return Array.prototype.push.apply(this,arguments);
}
return array;
}
var array = getArrayWithLimitedLength(10);
To remove first element from array use shift:
if (arr.length > 10) {
arr.shift(); // removes the first element from an array
}
How about this object?
function Cache(maxLength) {
this.values = [];
this.store = function(data) {
if(this.values.length >= maxLength) {
this.getLast();
}
return this.values.push(data);
}
this.getLast = function() {
return this.values.splice(0,1)[0];
}
}
cache = new Cache(3);
// => Cache {values: Array[0]}
cache.store(1)
// => 1
cache.store(2)
// =>2
cache.store(3)
// => 3
cache.store(4)
// =>3
cache.values
// => [2, 3, 4]
cache.getLast()
// => 2
cache.values
[3, 4]
You could create new method in Array.prototype to mimic your needs.
Array.prototype.push_with_limit = function(element, limit){
var limit = limit || 10;
var length = this.length;
if( length == limit ){
this.shift();
}
this.push(element);
}
var arr = []
arr.push_with_limit(4); // [4]
arr.push_with_limit(9); // [4, 9]
....
// 11th element
arr.push_with_limit(3); // [9, ..., 3] 10 elements
Simple fixed length queue:
Array.prototype.qpush = function( vals, fixed ) {
if (arguments.length) {
if (Array.isArray(vals)) {
for (var v of vals) {
this.push(v);
}
} else {
this.push(vals);
}
var _f = (typeof this.fixed != undefined) ? this.fixed : 0;
if (typeof fixed != undefined) {
_f = (Number(fixed)===fixed && fixed%1===0 ) ? fixed : _f;
}
this.fixed = _f;
if (this.fixed>0) this.splice(0, this.length - _f);
}
}
var q = new Array();
q.push(0);
q.qpush( [1, 2, 3], 10 );
q.qpush( [4] );
q.qpush( 5 );
q.qpush( [6, 7, 8, 9, 10, {k:"object"} ] );
console.log(q);
if(array.length == 10) {
array.splice(0, 1);
// this will delete first element in array
}
If you do a check whether the array has reached 10 entries with array.length, just remove the first element before pushing a new element. This can be done several ways as Tushar states, array.shift() would be the fastest, but you can indeed use array.splice() aswell.
It would look like this:
if(array.length > 10) {
array.shift();
array.push(getData(10));
}
On a side note, instead of using var array = new Array() I suggest you simply use var array = [];. This is because the new keyword in Javascript sometimes has bad side effects. If you for example want to create an array with 1 element being a digit, and you use var arr = new Array(12);, an array with 12 undefined elements will be created. Whereas var arr = [12]; will create an array with 1 element, the digit 12.
But I guess that's a minor thing to consider..
You could use an object instead...
var obj = {}; //your cache object
obj[window.performance.now()] = getData(val); //add value, index by microsecond timestamp
if(Object.keys(obj).length > 10){ // then if the length ever gets bigger than 10..
var array = Object.keys(obj).sort(); //sort the properties by microsecond asc
delete obj[array[0]]; //delete the oldest one
}
Here is a jsFiddle example showing how it works: https://jsfiddle.net/uhkvk4mw/
just check if the length is reached then pop it
if(arr.length > someNumber){
arr.pop(); // pop() will remove the last element
}

JQuery retriving the next greatest element

in JQuery i m having an array like
(1,2,6,8)
I have already selected the first element that is 1 which i have saved in a JQuery variable
submitterid = 1
On clicking a link I am trying to get the next greatest element in the Array than what I have selected in the submitterid..
How can I achieve this?
Edit:
How to find the last element in this array in the code
var previousId;
$("#previous").click(function (){
index = submitters.indexOf(submitterid),
nextId;
if (index - 1 < submitters.length) {
previousId = submitters[index-1];
} else {
// no ID index
// if i am having an array of 1,2,6,8 after moving to 1 from 8 to 6 - 2-1 i am trying to move to the last element of the array
}
alert(previousId);
});// previousId
Why couldn't you do something like:
var arr = [3, 5, 8, 3].sort(function (a, b) { return a - b; } );
var val = arr.pop();
Any keep popping the array -- saying that the values don't need to stay in the array.
If you are randomly picking values and you need the next highest, then write the appropriate sorting function.
You want a counter:
function counter(arr) {
this.arr = arr;
this.index = 0;
}
counter.prototype.next = function() {
return this.arr[this.index++];
}
You instantiate it and use it like:
var nums = new counter([1,2,3,4,5]);
nums.next() ; => 1
nums.next() ; => 2
nums.next() ; => 3
Actually, there is no need to use any jquery-specific stuff for this, apart from the click event handling, just 'plain javascript' will do;
var myArray = [ 1, 2, 6, 8 ];
var submitterid = 1;
$(function() {
$('a#id').click(function(event) {
event.preventDefault();
var greater = -1;
// loop through array
for (var i in myArray)
// find numbers greater than the specified number
if (i > submitterid)
// find numbers closest to specified number
if (i < greater || greater < 0)
greater = i;
if (greater < 0) {
// no greater value found, do something
} else {
// next biggest value is in variable greater, do something with it
}
});
});
You have to loop through the array.
Try this untested code:
// Your test array.
var arrValues = [ "1", "2", "6", "8" ];
var low = 1;
var high = 2;
// Loop over each value in the array.
$.each( arrValues, function( intIndex, objValue ){
if (objValue > high)
hight = objValue;
if (objValue < high)
if (objValue > low)
low = objValue
});
return low;
If your array is already sorted (see sort method), try this:
var arr = [1,2,6,8],
submitterid = 1,
index = arr.indexOf(submitterid),
nextId;
if (index + 1 < arr.length) {
nextId = arr[index+1];
} else {
// no ID index
}

Categories