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])
Related
I have an array of 3 value arrays, and I need to convert them into a set of arrays where each array is made up of the values which were common between arrays, so my input of
[[2,3,9], [1,4,7], [3,6,9], [1,7,5], [7,5,8], [9,6,10], [3,6,10], [1,8,5]]
becomes
[[2,3,6,9,10],[1,4,5,7,8]]
Order is not important. I've found similar questions such as Group same values in an array within an array in JS but it seems slightly different to my case, but I imagine using reduce is the way to go, but I don't entirely understand how. I have tried creating an object using the following format, but couldn't get from there to an answer:
{
vertex: 3,
triangles: [2,3,9], [3,6,9], [3,6,10]
}
Here is one algorithm. Take first item from array and check first item array has any common array. If they have common item, then merge it and move the merged array to first item of array. If no common item, then add to result array.
const merge = (arr) => {
const result = [];
while (arr.length > 0) {
let first = arr.shift();
const idx = arr.findIndex((items) =>
items.some((item) => first.includes(item))
);
if (idx !== -1) {
first = first.concat(arr[idx]);
arr.splice(idx, 1);
arr.unshift(first);
} else {
result.push(first);
}
}
return result.map(items => [...new Set(items)]);
};
const data = [
[2, 3, 9],
[1, 4, 7],
[3, 6, 9],
[1, 7, 5],
[7, 5, 8],
[9, 6, 10],
[3, 6, 10],
[1, 8, 5],
];
console.log(merge(data));
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);
I need to create a new array made up of unique elements from two separate arrays.
I have converted both arrays into a single array and then converted this into an object to check the frequency of the elements. If the value of an object property is 1 (making it a unique property), I want to return it to an array (minus the value). Is there a straightforward way to achieve this?
Edits: Moved result outside for loop. Expected output should be [4]
function diffArray(arr1, arr2) {
var finalArr = [];
var countObj = {};
var newArr = [...arr1, ...arr2];
for (var i = 0; i < newArr.length; i++) {
if (!countObj[newArr[i]]) countObj[newArr[i]] = 0;
++countObj[newArr[i]];
}
for (var key in countObj) {
if (countObj[key] === 1) {
finalArr.push(key);
}
} return finalArr;
}
diffArray([1, 2, 3, 5], [1, 2, 3, 4, 5]);
If I understand correctly, you're wanting to find the difference between arr1 and arr2, and returns that difference (if any) as a new array of items (that are distinct in either array).
There are a number of ways this can be achieved. One approach is as follows:
function diffArray(arr1, arr2) {
const result = [];
const combination = [...arr1, ...arr2];
/* Obtain set of unique values from each array */
const set1 = new Set(arr1);
const set2 = new Set(arr2);
for(const item of combination) {
/* Iterate combined array, adding values to result that aren't
present in both arrays (ie exist in one or the other, "difference") */
if(!(set1.has(item) && set2.has(item))) {
result.push(item);
}
}
return result;
}
console.log(diffArray([1, 2, 3, 5], [1, 2, 3, 4, 5]), " should be [4]");
console.log(diffArray([1, 2, 3, 5, 8], [1, 2, 3, 5]), " should be [8]");
console.log(diffArray([1, 2, 3, 5, 8], [1, 2, 3, 5, 9]), " should be [8, 9]");
console.log(diffArray([1, 2], [1, 2]), " should be []");
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);
When I want to remove one element, it is easy. This is my function:
function removeValues(array, value) {
for(var i=0; i<array.length; i++) {
if(array[i] == value) {
array.splice(i, 1);
break;
}
}
return array;
}
But how do I remove multiple elements?
Here a simple version using ES7:
// removing values
let items = [1, 2, 3, 4];
let valuesToRemove = [1, 3, 4]
items = items.filter((i) => !valuesToRemove.includes(i))
For a simple version for ES6
// removing values
let items =[1, 2, 3, 4];
let valuesToRemove = [1, 3, 4]
items = items.filter((i) => (valuesToRemove.indexOf(i) === -1))
const items = [0, 1, 2, 3, 4];
[1, 4, 3].reverse().forEach((index) => {
items.splice(index, 1)
})
// [0, 2, 4]
I believe you will find the kind of functionality you are looking for in Javascript's built in array functions... particularily Array.map(); and Array.filter();
//Array Filter
function isBigEnough(value) {
return value >= 10;
}
var filtered = [12, 5, 8, 130, 44].filter(isBigEnough);
// filtered is [12, 130, 44]
//Array Map (Can also be used to filter)
var numbers = [1, 4, 9];
var doubles = numbers.map(function(num) {
return num * 2;
});
// doubles is now [2, 8, 18]. numbers is still [1, 4, 9]
/////UPDATE REFLECTING REMOVAL OF VALUES USING ARRAY MAP
var a = [1,2,3,4,5,6];
a.map(function(v,i){
if(v%2==0){
a.pop(i);
}
});
console.log(a);
// as shown above all array functions can be used within the call back to filter the original array. Alternativelty another array could be populated within the function and then aassigned to the variable a effectivley reducing the array.