Merge arrays and toggle - javascript

I have two arrays of ids:
let a = [1, 7, 8];
let b = [1, 7, 99];
I want to merge they and toggle off the common values. The result must be as follow:
let res = [8, 99];
Each array (a or b) can't have duplicates. So next is impossible
let a = [1, 1, 7, 8];
let b = [1, 7, 7, 99, 7];
How can I merge and toggle? I can merge this way without duplicates, but it is not I want.
[...new Set([...a, ...b])]; // [1, 7, 8, 99]

Using Array#filter on both with spread operator.
let a = [1, 7, 8];
let b = [1, 7, 99];
const res = [...a.filter(item=>!b.includes(item)), ...b.filter(item=>!a.includes(item))];
console.log(res);

To avoid a O(n²) time complexity, make a set for one of both arrays
const a = [1, 7, 8];
const b = [1, 7, 99];
const setA = new Set(a);
const res = [...b.filter(item => !setA.delete(item)), ...setA];
console.log(res);

You could take a single set and reduce the second array.
let a = [1, 7, 8],
b = [1, 7, 99],
result = [...b.reduce((s, v) => s.has(v) ? (s.delete(v), s) : s.add(v), new Set(a))];
console.log(result);

Here is another approach by using a for-loop
const a = [1, 7, 8];
const b = [1, 7, 99];
const arr = a.concat(b).sort((a, b) => a - b);
const result = [];
let currentId;
for (const id of arr) {
if (currentId === id) {
result.pop();
} else {
currentId = id;
result.push(id);
}
}
console.log(result);

So, what you want is to calculate the union of the two arrays minus the intersection of they. Skipping the performance, I will do this step by step:
let a = [1, 7, 8];
let b = [1, 7, 99];
// Calculate the union.
let union = new Set([...a, ...b]);
// Calculate the intersection.
let intersection = new Set(a.filter(x => b.includes(x)));
// Calculate union minus intersection.
let res = [...union].filter(x => !intersection.has(x));
console.log(res);
Or in a simplified way (not so readable like the previous one):
let a = [1, 7, 8];
let b = [1, 7, 99];
// Calculate union minus intersection.
let res = [...a, ...b].filter(x => !(a.filter(y => b.includes(y))).includes(x));
console.log(res);
Even more simplified and readable would be one of the next options:
let a = [1, 7, 8];
let b = [1, 7, 99];
// Calculate union minus intersection.
let res1 = [...a, ...b].filter(x => !(a.includes(x) && b.includes(x)));
console.log(res1);
// Or using Morgan’s Law:
let res2 = [...a, ...b].filter(x => !a.includes(x) || !b.includes(x));
console.log(res2);

Related

Return a new array with all values except the first, adding 7 to each

How to return a new array with all values except the first, adding 7 to each
For example, addSevenToMost([1, 3, 5]) should return [10, 12]
I tried
let arr = [1, 3, 5];
function addSevenToMost(arr) {
let except = 0;
const newArr = arr.filter((value, index) => index !== except);
return newArr;
}
I only managed to get the new array values except the first, now I don't know how to add 7 to each.
let arr = [1, 3, 5];
let result = arr.slice(1).map(e => e + 7)
console.log(result)
const arr = [1, 3, 5]
const result = arr.slice(1).map(item => item + 7)
console.log(result)

javascript array index ascending by value value

I have an array which one including below values:
tomb = [4, 6, 1, 3, 5, 0, 2]
tomb[0] = 4
tomb[1] = 6
tomb[2] = 1
tomb[3] = 3
tomb[4] = 5
tomb[5] = 0
tomb[6] = 2
Can I ask is possible to convert like this:
tomb[5] = 0
tomb[2] = 1
tomb[6] = 2
tomb[3] = 3
tomb[0] = 4
tomb[4] = 5
tomb[1] = 6
I would like to use in for loop this array values, but before I have to start from the minimum and increase to the biggest one. So I would like get a array index list from minimum to maximum.
const arr = [4, 6, 1, 3, 5, 0, 2];
const min = Math.min.apply(null, arr);
const index = arr.indexOf(min);
console.log(index);
You could get the keys of the array and sort the indices by the values of the given array.
const
array = [4, 6, 1, 3, 5, 0, 2],
indices = [...array.keys()].sort((a, b) => array[a] - array[b]);
console.log(...indices);
Try this one by using array.sort and array.indexOf
const arr = [4, 6, 1, 3, 5, 0, 2];
const newarr = arr.slice()
const arrindex = []
newarr.sort()
newarr.forEach(i=>{
arrindex.push(arr.indexOf(i))
})
console.log(arrindex)
Just use Array.sort()
const arr = [4, 6, 1, 3, 5, 0, 2];
const sorted = arr
.map((value, index) => ({ index, value }))
.sort((a, b) => a.value - b.value)
console.log(
sorted.map(entry => entry.index),
sorted.map(entry => entry.value)
)

How to compare two arrays and add/remove elements depending on their difference?

Let's say I have two arrays, where array1 is always changing:
First case:
array1 = [1, 2, 3, 4, 5]
array2 = [1, 2, 3]
How can I compare them and add 4 and 5 into array2?
I am getting the difference between them doing:
let difference = array1.filter(x => !array2.includes(x));
and then doing array2.push(difference), so array2 is now equal to array1, right?
Second case:
array1 = [1, 2, 8, 9]
array2 = [1, 2, 3]
So now I need to remove 3 from array2, and add 8 and 9, how can I do this?
EDIT: I need this because I'm getting array1 from a server(they are chats) and it's dynamically changing every 5 sec, and this is problem. I need to keep the elements I already have so they won't "update" and only change the one getting deleted or added. Hope this makes sense.
First case will not work as aspectedlooking at the code,
to achive what you want you have to write:
difference.forEach((x) => array2.push(x));
instead of:
array2.push(difference)
for the second one if you want to remove a record in array2 because is missing in array1 you need to control each value of array2 in array1 and remove if not exists by ID
var array1 = [1, 2, 8, 9];
var array2 = [1, 2, 3];
//here i build difference2 collecting the value of array2 that miss on array1
let difference2 = array2.filter((x) => !array1.includes(x));
//here with splice and indexOf i remove every value collected before
difference2.forEach((x) => array2.splice(array2.indexOf(x), 1));
//following code is to add the 8 and 9
let difference = array1.filter((x) => !array2.includes(x));
difference.forEach((x) => array2.push(x));
console.log(array2);
//the result [1,2,8,9]
let array1 = [1, 2, 3, 4, 5];
let array2 = [1, 2, 3];
let filteredArray = array2.filter((a) => array1.includes(a));
let secFilteredArray = array1.filter((a) => !filteredArray.includes(a));
console.log(filteredArray.concat(secFilteredArray));
You could take a Set and delete seen items and add the rest to the array.
const
array1 = [1, 2, 8, 9],
array2 = [1, 2, 3],
set1 = new Set(array1);
let i = array2.length;
while (i--) if (!set1.delete(array2[i])) array2.splice(i, 1);
array2.push(...set1);
console.log(array2);
Just use another filter and combine the two arrays.
const array1 = [1, 2, 8, 9];
let array2 = [1, 2, 3];
const inArrOne = array1.filter(x => !array2.includes(x));
const inBothArr = array2.filter(x => array1.includes(x));
array2 = [...inBothArr, ...inArrOne];
console.log(array2);
I would avoid much built-in or third party compare functions since I am not sure what I am dealing with. This could be refactored and optimized more if the array1 is guaranteed to have an ordered list.
let localArray = [1, 2, 3, 4, 5],
lastServerArray = [];
/**
* Compares "fromArr" to "targetArr"
* #param fromArr Array of elements
* #param targetArr Array of elements
* #returns List of elements from "fromArr" that do not happen in "targetArr"
*/
const compArr = (fromArr, targetArr) => {
const result = [];
for (let i = 0, len = fromArr.length; i < len; i++) {
const elem = fromArr[i],
targetIdx = targetArr.indexOf(elem);
if (!~targetIdx && !~result.indexOf(elem)) {
// Element do not exist in "targetArr" and in current "result"
result.push(elem);
}
}
return result;
}
const updateLocalArray = (serverArray = []) => {
if (JSON.stringify(lastServerArray) === JSON.stringify(serverArray)) {
console.log('Nothing changed from server, skip updating local array');
return localArray;
}
lastServerArray = serverArray;
const notExistentLocalElems = compArr(serverArray, localArray), // Elements that do not exists in local array
notExistentServerElems = compArr(localArray, serverArray); // Elements that do not exists in server array
// Do something to those "notExistentLocalElems" or "notExistentServerElems"
// ---
// Sync server array to local array
// Remove elements that is not on server.
localArray = localArray.filter(elem => !~notExistentServerElems.indexOf(elem));
console.log('These elements removed from localArray', notExistentServerElems);
// Append elements that is on server.
localArray.push(...notExistentLocalElems);
console.log( 'These elements added into localArray', notExistentLocalElems);
return localArray;
}
updateLocalArray([1, 2, 3]);
console.log(`1. server sends [1, 2, 3] -- local becomes`, localArray);
updateLocalArray([3, 4, 5, 6]);
console.log(`2. server sends [3, 4, 5, 6] -- local becomes`, localArray);
updateLocalArray([5, 5, 4, 2, 7]);
console.log(`3. server sends [5, 5, 4, 2, 7] -- local becomes`, localArray);
updateLocalArray([0, 0, 1, 2]);
console.log(`4. server sends [0, 0, 1, 2] -- local becomes`, localArray);
You could do like this if you want to mutate array2:
let array1 = [1, 2, 8, 9];
let array2 = [1, 2, 3];
let valuesToAdd = array1.filter(x => !array2.includes(x));
let indexesToDelete = Object.entries(array2).filter(([, x]) => !array1.includes(x)).map(([i]) => i);
// Reverse iteration to preserve indexes while removing items
indexesToDelete.reverse().forEach(i => array2.splice(indexesToDelete[i], 1));
array2.push(...valuesToAdd);
console.log(array2);

How to remove first array element using the spread syntax

So I have an array, ex. const arr = [1, 2, 3, 4];. I'd like to use the spread syntax ... to remove the first element.
ie. [1, 2, 3, 4] ==> [2, 3, 4]
Can this be done with the spread syntax?
Edit: Simplified the question for a more general use case.
Sure you can.
const xs = [1,2,3,4];
const tail = ([x, ...xs]) => xs;
console.log(tail(xs));
Is that what you're looking for?
You originally wanted to remove the second element which is simple enough:
const xs = [1,0,2,3,4];
const remove2nd = ([x, y, ...xs]) => [x, ...xs];
console.log(remove2nd(xs));
Hope that helps.
Destructuring assignment
var a = [1, 2, 3, 4];
[, ...a] = a
console.log( a )
Is this what you're looking for?
const input = [1, 0, 2, 3, 4];
const output = [input[0], ...input.slice(2)];
After the question was updated:
const input = [1, 2, 3, 4];
const output = [...input.slice(1)];
But this is silly, because you can just do:
const input = [1, 2, 3, 4];
const output = input.slice(1);
You could use the rest operator (...arrOutput) with the spread operator(...arr).
const arr = [1, 2, 3, 4];
const [itemRemoved, ...arrOutput] = [...arr];
console.log(arrOutput);

Fast way to push and shift arrays in ES6

I have a data stream which continuously needs to update an array. The array itself is always bigger than the stream which is coming in. This would mean that I have to concat the buffer to the array and shift everything. However, concatenation is slow so I was wondering if there is a fast way of doing this?
Example:
var array = [1,2,3,4,5,6];
var stream = [7,8,9];
array = magicalFunction(array,stream); // outputs [4,5,6,7,8,9]
The array function is used for plotting with ChartJS. It's a rolling plot so as data comes in (it comes in chunks) I have to update the chart by shifting the entire data set.
You could use spread syntax .... But if that is faster than concat ...?
var magicalFunction = (a, s) => [...a.slice(s.length - a.length), ...s],
array = [1, 2, 3, 4, 5, 6],
stream = [7, 8, 9];
array = magicalFunction(array,stream);
console.log(array);
With Array.concat
var magicalFunction = (a, s) => a.slice(s.length - a.length).concat(s);
array = [1, 2, 3, 4, 5, 6],
stream = [7, 8, 9];
array = magicalFunction(array,stream);
console.log(array);
With Array.unshift
var magicalFunction = (a, s) => (s.unshift(...a.slice(s.length - a.length)), s);
array = [1, 2, 3, 4, 5, 6],
stream = [7, 8, 9];
array = magicalFunction(array,stream);
console.log(array);
You can apply a .push:
array.push.apply(array, stream);
or in ES2015 you can use the triple dots:
array.push(...stream)
How about a Spread
var stream = [7,8,9];
var array = [1,2,3,4,5,6, ...stream];
Maybe it's late to answer but you could do this with ES6 like this:
let array = [1, 2, 3, 4, 5, 6];
let stream = [7, 8, 9, 1];
const mergedArray = [...array, ...stream]
// fetch only distinct values
const distinctMergedArray = Array.from(new Set(mergedArray))
let array = [1, 2, 3, 4, 5, 6];
let stream = [7, 8, 9, 1];
//set to get distinct value and spread operator to merge two arrays
const resultArray = new Set([...array, ...stream])

Categories