Lets say that I am to remove the oldest element of an array, because I wanted to replace it with a new value. (first-in-first-out).
For example, I have this array of values
var arr = [1,2,3,4,5,6,7]
And I wanted to only get the first three, values, and then on the 4th, replace the element who came first
[1,2,3], [4,2,3], [4,5,3] and so on..
I came up with a solution
var arr = [1,1,2,3,4,5,6,7];
var newArr = [];
for(i=0; i<arr.length; i++){
if(newArr.length == 3 && newArr.indexOf(arr[i]) < 0) {
newArr[i%3] = arr[i];
} else if(newArr.indexOf(arr[i]) < 0) {
newArr.push(arr[i])
}
console.log(newArr)
}
Which will render:
1
1
1,2
1,2,3
1,4,3
1,4,5
6,4,5
6,7,5
Instead of
1
1,2
1,2,3
4,2,3
4,5,3
4,5,6
7,5,6
What am I missing out.
var arr = [1, 1, 2, 3, 4, 5, 6, 7];
var newArr = [], currentIndex = 0;
for (i = 0; i < arr.length; i++) {
if (newArr.length === 3 && newArr.indexOf(arr[i]) < 0) {
newArr[currentIndex % 3] = arr[i];
currentIndex += 1;
} else if (newArr.indexOf(arr[i]) < 0) {
newArr.push(arr[i]);
}
console.log(newArr)
}
Output
[ 1 ]
[ 1 ]
[ 1, 2 ]
[ 1, 2, 3 ]
[ 4, 2, 3 ]
[ 4, 5, 3 ]
[ 4, 5, 6 ]
[ 7, 5, 6 ]
You just need to track the current index where you need to place the number using a separate variable.
Related
Why the following array doesn't push correctly in the loop to r?
If I change to if((pivot + originArr[c]) <= 5) instead of if((pivot + originArr[c]) <= 3)
My result is wrong:
[ [ 0, 1, 2, 3, 4 ],
[ 0, 1, 2, 3, 4 ],
[ 0, 1, 2, 3, 4 ],
[ 0, 2, 3 ],
[ 1, 2, 3 ] ]
Expected result should be[ [ 0, 1, 2], [ 0, 1, 3], [ 0, 1, 4], [ 0, 2, 3 ] ]
If r is not empty, it will recursive and send the first iteration result to the function to do computation until the "r" is empty. It doesn't push individual group of array to "r" for every c loop.
var data = [0, 1, 2, 3, 4, 5];
function compute(originArr, filterArr) {
var r = [];
var arr;
let firstLoop = false;
if (filterArr.length == 0) {
firstLoop = true;
arr = originArr;
} else {
arr = filterArr;
}
arr.forEach(function(i, index) {
var pivot;
if (firstLoop) {
pivot = index;
} else {
pivot = parseInt(i.slice(-1));
}
var nextIndex = pivot + 1;
console.log(pivot, nextIndex);
for (var c = nextIndex; c < originArr.length; c++) {
let tempResult = [];
console.log(c);
if (pivot + originArr[c] <= 3) {
if (firstLoop) {
tempResult.push(index);
} else {
tempResult = i;
}
tempResult.push(c);
console.log(tempResult);
r.push(tempResult); // suppose to push [0,1], [0,2], [0,3], [1,2] for the first iteration
}
}
});
if (r.length > 0) {
return compute(originArr, r);
} else {
return arr;
}
}
console.log(compute(data, []));
//Final result should be [[0,1,2]]
I think I found out the problem.
We can't clone the array like this
tempResult = i;
it will affect the reference 'i' after I have pushed the new number into the temResult.
So my solution is to change the cloning way to:
tempResult = [...i];
That cloning will not affects the reference.
I'm trying to find single occurrence of an element in an array. But it only shows for 1 element. Where is the logic going wrong?
function findSingle(array){
var arrayCopy = array.slice(0);
var x;
var y = [];
for (var i = 0; i < array.length; i++) {
x = arrayCopy.splice(i, 1)
if(arrayCopy.includes(array[i]) === false){
console.log(array[i] + " is single")
}
arrayCopy = arrayCopy.concat(x)
}
}
findSingle([1, 3, 3, 6])
You can use a double Array.filter() to remove numbers that appear more than once:
function findSingle(arr) {
return arr.filter(i => arr.filter(j => i === j).length === 1)
}
const result = findSingle([1, 3, 3, 6, 8, 4, 6])
console.log(result) // [1, 8, 4]
Bear in mind that this will only work for Numbers and other primitives because of the way that Javascript evaluates equality and sameness.
I added some console.logs to see what was happening and the problem is that you're changing the order of elements in arrayCopy. And so 6 is never checked.
Checking for [ 1 ]
arrayCopy is [ 3, 3, 6 ]
1 is single
After adding to arrayCopy [ 3, 3, 6, 1 ]
Checking for [ 3 ]
arrayCopy is [ 3, 6, 1 ]
After adding to arrayCopy [ 3, 6, 1, 3 ]
Checking for [ 1 ]
arrayCopy is [ 3, 6, 3 ]
After adding to arrayCopy [ 3, 6, 3, 1 ]
Checking for [ 1 ]
arrayCopy is [ 3, 6, 3 ]
After adding to arrayCopy [ 3, 6, 3, 1 ]
You can probably use a frequency map to find the number of occurrences in each element and then filter keys that occur only once.
function findSingle(array){
var freqs = {};
array.forEach(n => {
if (!(n in freqs)) freqs[n] = 1;
else freqs[n] += 1;
});
return Object.keys(freqs).filter(k => freqs[k] === 1);
}
This could be done by creating an object that could map element and its occurrence.
So here is a code
function findSingle(arr){
var counts = {};
var singles = [];
for (var i = 0; i < arr.length; i++) {
var num = arr[i];
counts[num] = counts[num] ? counts[num] + 1 : 1;
}
for(var num in counts) {
if(counts[num] == 1)
singles.push(num);
}
return singles.map(x => Number(x));
}
The output of findSingle([1, 3, 3, 6]) will be
[1, 6]
Note This can work with string too but it may be numbers. For example, ["1", "3", "3", "6"]
Question has been moved to CodeReview: https://codereview.stackexchange.com/questions/154804/find-a-list-of-objects-in-an-array-with-javascript
Having an array of objects - such as numbers - what would be the most optimal (Memory and CPU efficiency) way if finding a sub group of objects? As an example:
demoArray = [1,2,3,4,5,6,7]
Finding [3,4,5] would return 2, while looking for 60 would return -1.
The function must allow for wrapping, so finding [6,7,1,2] would return 5
I have a current working solution, but I'd like to know if it could be optimized in any way.
var arr = [
1,
5,2,6,8,2,
3,4,3,10,9,
1,5,7,10,3,
5,6,2,3,8,
9,1]
var idx = -1
var group = []
var groupSize = 0
function findIndexOfGroup(g){
group = g
groupSize = g.length
var beginIndex = -2
while(beginIndex === -2){
beginIndex = get()
}
return beginIndex
}
function get(){
idx = arr.indexOf(group[0], idx+1);
if(idx === -1 || groupSize === 1){
return idx;
}
var prevIdx = idx
for(var i = 1; i < groupSize; i++){
idx++
if(arr[getIdx(idx)] !== group[i]){
idx = prevIdx
break
}
if(i === groupSize - 1){
return idx - groupSize + 1
}
}
return -2
}
function getIdx(idx){
if(idx >= arr.length){
return idx - arr.length
}
return idx
}
console.log(findIndexOfGroup([4,3,10])) // Normal
console.log(findIndexOfGroup([9,1,1,5])) // Wrapping
You could use the reminder operator % for keeping the index in the range of the array with a check for each element of the search array with Array#every.
function find(search, array) {
var index = array.indexOf(search[0]);
while (index !== -1) {
if (search.every(function (a, i) { return a === array[(index + i) % array.length]; })) {
return index;
}
index = array.indexOf(search[0], index + 1);
}
return -1;
}
console.log(find([3, 4, 5], [1, 2, 3, 4, 5, 6, 7])); // 2
console.log(find([6, 7, 1, 2], [1, 2, 3, 4, 5, 6, 7])); // 5
console.log(find([60], [1, 2, 3, 4, 5, 6, 7])); // -1
console.log(find([3, 4, 5], [1, 2, 3, 4, 6, 7, 3, 4, 5, 9])); // 6
.as-console-wrapper { max-height: 100% !important; top: 0; }
My take on the problem is to use slice() and compare each subarray of length equal to the group's length to the actual group array. Might take a bit long, but the code is short enough:
// The array to run the tests on
var arr = [
1,
5, 2, 6, 8, 2,
3, 4, 3, 10, 9,
1, 5, 7, 10, 3,
5, 6, 2, 3, 8,
9, 1
];
// Check arrays for equality, provided that both arrays are of the same length
function arraysEqual(array1, array2) {
for (var i = array1.length; i--;) {
if (array1[i] !== array2[i])
return false;
}
return true;
}
// Returns the first index of a subarray matching the given group of objects
function findIndexOfGroup(array, group) {
// Get the length of both arrays
var arrayLength = array.length;
var groupLength = group.length;
// Extend array to check for wrapping
array = array.concat(array);
var i = 0;
// Loop, slice, test, return if found
while (i < arrayLength) {
if (arraysEqual(array.slice(i, i + groupLength), group))
return i;
i++;
}
// No index found
return -1;
}
// Tests
console.log(findIndexOfGroup(arr,[4,3,10])); // Normal
console.log(findIndexOfGroup(arr,[9,1,1,5])); // Wrapping
console.log(findIndexOfGroup(arr,[9,2,1,5])); // Not found
If the group is longer than the array, some errors might occur, but I leave it up to you to extend the method to deal with such situations.
This question already has answers here:
How to get the difference between two arrays in JavaScript?
(84 answers)
Closed 6 years ago.
Say I have the following two arrays:
var arrOne = [1, 4, 7];
var arrTwo = [1, 2, 3, 4, 5];
var arrThree = [];
I'd like to itterate over arrTwo and if it contains an element that is also in arrOne, remove it from arrTwo, and insert it in arrThree. So looking at the above arrays the state of the arrays afterwards should look like this:
var arrOne = [1, 4, 7];
var arrTwo = [2, 3, 5];
var arrThree = [1, 4];
Could anyone point me in the right direction and the best way to go about this? If code is provided, a step-by-step explanation would really be appreciated so that I can understand what's going on.
A simple for loop, matching with indexOf and splicing matches.
var arrOne = [1, 4, 7];
var arrTwo = [1, 2, 3, 4, 5];
var arrThree = [];
for (var i = 0; i < arrTwo.length; i++) {
if (arrOne.indexOf(arrTwo[i]) >= 0) {
arrThree.push(arrTwo[i]);
arrTwo.splice(i, 1);
i--;
}
}
console.log(arrOne, arrTwo, arrThree)
Array.IndexOf
Array.splice
Look into the Underscore library. All the elements in arrOne that are also in arrTwo is called _.intersection().
Use simple while loop with Array#splice and Array#unshift methods.
var arrOne = [1, 4, 7];
var arrTwo = [1, 2, 3, 4, 5];
var arrThree = [];
// get length of array
var l = arrTwo.length;
// iterate over array from the end
while (l--) {
// check value present in arrOne
if (arrOne.indexOf(arrTwo[l]) > -1)
// if present then remove and insert it
// at the beginning of arrThree
arrThree.unshift(arrTwo.splice(l, 1)[0])
}
console.log(arrTwo, arrThree);
Hi You can use filter function to filter array.
try with below code.
var arrOne = [1, 4, 7];
var arrTwo = [2, 3, 5, 1];
var arrThree = [];
function checkValue(a) {
return !arrOne.indexOf(a);
}
function checkValue2(a) {
return arrThree.indexOf(a);
}
function myFunction() {
arrThree = arrTwo.filter(checkValue);
document.getElementById("demo").innerHTML = arrThree ;
arrTwo = arrTwo.filter(checkValue2);
document.getElementById("demo1").innerHTML = arrTwo;
}
var arrOne = [1, 4, 7];
var arrTwo = [1, 2, 3, 4, 5];
var arrThree = diff(arrOne,arrTwo);//passes the two arrays
console.log(arrThree);
function diff(one, two){
one.forEach(function(e1){ //iterate through the first array
two.forEach(function(e2){//iterate through second
if(e1 == e2) //checking if elements are equal
two.pop(e2);//removing from second array
});
});
return two; //returning new array
}
You can use underscore js for easy array operations, the difference operation will be _.difference([1, 2, 3, 4, 5], [5, 2, 10]);.
var array1 = [1, 2, 3, 4, 5, 6],
var array2 = [1, 2, 3, 4, 5, 6, 7, 8, 9];
var common = $.grep(array1, function(element) {
return $.inArray(element, array2) !== -1;
});
console.log(common); // returns [1, 2, 3, 4, 5, 6];
array2 = array2.filter(function(obj) {
return array1.indexOf(obj) == -1;
});
// returns [7,8,9];
Since the arrays are sorted you could read them in parallel : O(n) instead of O(n2). Don't use a library for such a simple problem, this is overkill :-)
var i = 0, j = 0;
var a = [1, 4, 7];
var b = [1, 2, 3, 4, 5];
var c = [];
while (i < a.length && j < b.length) {
if (a[i] < b[j]) i++;
else if (a[i] > b[j]) j++;
else c.push(b.splice(j, 1)[0]);
}
console.log("a " + toString(a));
console.log("b " + toString(b));
console.log("c " + toString(c));
function toString (v) {
return "[ " + v.join(" ") + " ]";
}
Trace :
#0 init
a = [ 1 4 7 ]
i
b = [ 1 2 3 4 5 ]
j
c = []
#1 a[i] = b[j] => move b[j] to c
a = [ 1 4 7 ]
i
b = [ 2 3 4 5 ]
j
c = [ 1 ]
#2 a[i] < b[j] => increment i
a = [ 1 4 7 ]
i
b = [ 2 3 4 5 ]
j
c = [ 1 ]
#3 a[i] > b[j] => increment j
a = [ 1 4 7 ]
i
b = [ 2 3 4 5 ]
j
c = [ 1 ]
#4 a[i] > b[j] => increment j
a = [ 1 4 7 ]
i
b = [ 2 3 4 5 ]
j
c = [ 1 ]
#5 a[i] = b[j] => move b[j] to c
a = [ 1 4 7 ]
i
b = [ 2 3 5 ]
j
c = [ 1 4 ]
#6 a[i] < b[j] => increment i
a = [ 1 4 7 ]
i
b = [ 2 3 5 ]
j
c = [ 1 4 ]
#7 a[i] > b[j] => increment j
a = [ 1 4 7 ]
i
b = [ 2 3 5 ]
j
c = [ 1 4 ]
#8 j = length of b => done
I need to delete occurrences of an element if it occurs more than n times.
For example, there is this array:
[20,37,20,21]
And the output should be:
[20,37,21]
I thought one way of solving this could be with the splice method
First I sort the array it order to make it like this:
[20,20,37,21]
Then I check if the current element is not equal to the next and split the array into chunks, so it should look like:
[20, 20],[37],[21]
Later I can edit the chunk longer than 1 and join it all again.
This is what the code looks like in my head but didn't work in real life
var array = [20, 37, 20, 21];
var chunk = [];
for(i = 0; i < array.length; i++) {
if(array[i] !== array[i + 1]) {
var index = array.indexOf(array[i]);
chunk.push = array.splice(0, index) // cut from zero to last duplicate element
} else
var index2 = a.indexOf(a[i]);
chunk.push(a.splice(0, index));
}
with this code the output is
[[], [20, 20]]
I think It's something in the 'else' but can't figure it out what to fix.
As the logic you want to achieve is to delete n occurrences of element in an array, your code could be as follow:
var array = [1, 1, 3, 3, 7, 2, 2, 2, 2];
var n = 2;
var removeMultipleOccurences = function(array, n) {
var filteredArray = [];
var counts = {};
for(var i = 0; i < array.length; i++) {
var x = array[i];
counts[x] = counts[x] ? counts[x] + 1 : 1;
if (counts[x] <= n) filteredArray.push(array[i])
}
return filteredArray;
}
console.log(removeMultipleOccurences(array, n));
I came up with this one, based on array filter checking repeated values up to a limit, but I can see #Basim's function does the same.
function removeDuplicatesAbove(arr, max) {
if (max > arr.length) {max = arr.length;}
if (!max) {return arr;}
return arr.filter(function (v, i) {
var under = true, base = -1;
for (var n = 0; n < max; n++) {
base = arr.indexOf(v, base+1); if (base == -1) {break;}
}
if (base != -1 && base < i) {under = false;}
return under;
});
}
var exampleArray = [20, 37, 20, 20, 20, 37, 22, 37, 20, 21, 37];
console.log(removeDuplicatesAbove(exampleArray, 3)); // [20, 37, 20, 20, 37, 22, 37, 21]
Always when you use splice() you truncate the array. Truncate the array with the length of same values from the start with the help of lastIndexOf(). It always starts from 0.
[ 1, 1, 1, 2, 2, 2, 3, 4, 4, 5 ] // splice(0, 3)
[ 2, 2, 2, 3, 4, 4, 5 ] // splice(0, 3)
[ 3, 4, 4, 5 ] // splice(0, 1)
[ 4, 4, 5 ] // splice(0, 2)
[ 5 ] // splice(0, 1)
Do this as long as the array length is greater than 0.
var arr = [1, 1, 1, 2, 2, 2, 3, 4, 4, 5];
var res = [];
while (arr.length > 0) {
var n = arr[0];
var last = arr.lastIndexOf(n) + 1;
res.push(n);
arr.splice(0, last);
}
console.log(res);
You can use Array.prototype.reduce(), Array.prototype.filter() to check if n previous elements are the same as current element
let cull = (arr, n) => arr.reduce((res, curr) => [...res
, res.filter(v => v === curr).length === n
? !1 : curr].filter(Boolean), []);
let arrays = [[20,37,20,21], [1,1,3,3,7,2,2,2,2]];
let cullone = cull(arrays[0], 1);
let cullthree = cull(arrays[1], 3);
console.log(cullone // [20, 37, 21]
, cullthree // [1, 1, 3, 3, 7, 2, 2, 2]
);