Javascript arrays of Objects; Subtract one from another - javascript

Put simply, I want to subtract one array from another.
The arrays are arrays of objects. I understand I can cycle through one array and on each item, comparing values in the other array, but that just seems a little messy.
Thanks for the help, hopefully this question isnt too basic, I have tried googling it with no luck :(
EDIT:
The Objects in the Arrays I wish to remove will have identical values but are NOT the same object (thanks #patrick dw). I am looking to completely remove the subset from the initial array.

This answer is copied from https://stackoverflow.com/a/53092728/7173655, extended with a comment and a solution with objects.
The code filters array A. All values included in B are removed from A.
const A = [1, 4, 3, 2]
const B = [0, 2, 1, 2]
console.log(A.filter(n => !B.includes(n)))
The same with objects:
const A = [{id:1}, {id:4}, {id:3}, {id:2}]
const B = [{id:0}, {id:2}, {id:1}, {id:2}]
console.log(A.filter(a => !B.map(b=>b.id).includes(a.id)))

http://phpjs.org/functions/index
There is no built-in method to do this in JavaScript. If you look at this site there are a lot of functions for arrays with similar syntax to PHP.

http://www.jslab.dk/library/Array
This site has some js functions on "sets"
I think you need the diff function.

It should remove all values from list a, which are present in list b keeping their order.
let a = [0, 2, 5, 6, 1];
let b = [2, 6, 2, 5, 0];
function arrayDiff() {
for (i of b) {
for (j of a) {
if (i === j) {
a.splice(a.indexOf(j), 1);
}
}
}
return a;
}

Related

Outputting same value for two separate sorting functions

Hey doing drills on sorting and I found something that I don't fully understand.
let numbers = [1,3,2,5,4];
let sortedHighesttoLowest = numbers.sort((a, b)=> b-a);
let sortedLowesttoHighest = numbers.sort((a, b)=> a-b);
console.log(sortedHighesttoLowest);
console.log(sortedLowesttoHighest);
output:
[ 1, 2, 3, 4, 5 ]
[ 1, 2, 3, 4, 5 ]
how come this outputs only the last function's value twice even though I assigned them to two separate variable?
Arrays are passed by reference. So when you assign to your variable a sorted array and then you sort again, the first variable will also be affected. You can use spread operator to avoid this.
let numbers = [1,3,2,5,4];
let sortedHighesttoLowest = [...numbers.sort((a, b)=> b-a)];
let sortedLowesttoHighest = [...numbers.sort((a, b)=> a-b)];
console.log(sortedHighesttoLowest);
console.log(sortedLowesttoHighest);
//output:
//[ 1, 2, 3, 4, 5 ]
//[ 1, 2, 3, 4, 5 ]
The comparator function works little different than some traditional languages that you might be used to.
In js, the return value of comparator is -1, 0 and 1. Although in lot of cases you can get away with using - minus operator.
Having said that, you're passing array as reference here which is causing the problem.
Try running this:
let numbers = [1,3,2,5,4];
let sortedHighesttoLowest = numbers.sort((a, b)=> a - b);
console.log(sortedHighesttoLowest);
let sortedLowesttoHighest = numbers.sort((a, b)=> b - a);
console.log(sortedLowesttoHighest);
Additionally I'd encourage you to go through here as well

In JS, what is "([...files])" [duplicate]

I came across this in some example code and I am completely lost.
const addCounter = (list) => {
return [...list, 0]; // This is the bit I am lost on, and I don't know about [...list, 0]
}
Apparently the above is equal to the following:
const addCounter = (list) => {
return list.concat([0]);
}
Any suggestion or explaination is much appreciated.
...list is using the spread syntax to spread the elements of list. Let's assume the list is [1, 2, 3]. Therefore [...list, 0] becomes:
[1, 2, 3, 0]
Which has the same result as doing list.concat([0]);
This is not a feature of the array in ES6, it's just been used for array concatenation. It has other uses. Read more on MDN, or see this question.
...list spreads (lays) out all the elements in the array list.
so [...list, 0] is all of the elements of list with a 0 at the end

Calculate the mathematical difference of each element between two arrays

Given two array of same length, return an array containing the mathematical difference of each element between two arrays.
Example:
a = [3, 4, 7]
b = [3, 9, 10 ]
results: c = [(3-3), (9-4), (10,7)] so that c = [0, 5 3]
let difference = []
function calculateDifferenceArray(data_one, data_two){
let i = 0
for (i in data_duplicates) {
difference.push(data_two[i]-data_one[i])
}
console.log(difference)
return difference
}
calculateDifferenceArray((b, a))
It does work.
I am wondering if there is a more elegant way to achieve the same
Use map as following:
const a = [3, 4, 7]
const b = [3, 9, 10]
const c = b.map((e, i) => e - a[i])
// [0, 5, 3]
for-in isn't a good tool for looping through arrays (more in my answer here).
"More elegant" is subjective, but it can be more concise and, to my eyes, clear if you use map:
function calculateDifferenceArray(data_one, data_two){
return data_one.map((v1, index) => data_two[index] - v1)
}
calculateDifferenceArray(b, a) // < Note just one set of () here
Live Example:
const a = [3, 4, 7];
const b = [3, 9, 10 ];
function calculateDifferenceArray(data_one, data_two){
return data_one.map((v1, index) => v1 - data_two[index]);
}
console.log(calculateDifferenceArray(b, a));
or if you prefer it slightly more verbose for debugging et. al.:
function calculateDifferenceArray(data_one, data_two){
return data_one.map((v1, index) => {
const v2 = data_two[index]
return v1 - v2
})
}
calculateDifferenceArray(b, a)
A couple of notes on the version of this in the question:
It seems to loop over something (data_duplicates?) unrelated to the two arrays passed into the method.
It pushes to an array declared outside the function. That means if you call the function twice, it'll push the second set of values into the array but leave the first set of values there. That declaration and initialization should be inside the function, not outside it.
You had two sets of () in the calculateDifferenceArray call. That meant you only passed one argument to the function, because the inner () wrapped an expression with the comma operator, which takes its second operand as its result.
You had the order of the subtraction operation backward.
You could use higher order array method map. It would work something like this:
let a = [2,3,4];
let b = [3,5,7];
let difference = a.map((n,i)=>n-b[i]);
console.log(difference);
you can read more about map here

sorting an array in the same order as another one

My problem is that I have two arrays to be sorted in the same order.
They are as follows:
objects = [obj1, obj2, obj3, obj4];
zorder = [1, 3, 4, 2]
I need to order the zorder, so that it is 1, 2, 3, 4,,that's quite easy, but I need the objects to be sorted the same way, like so:
objects = [obj1, obj4, obj2, obj3]
zorder = [1, 2, 3, 4]
I know this question has been asked before but none of the answers are working for me. All the answers I found would turn it into this:
objects = [{name:obj1, order:1},
{name:obj2, order:3},
{name:obj3, order:4},
{name:obj4, order:2}]
and then sort it from there. I cannot do that because the objects array needs to stay exactly the same except for the order, the same is true for zorder. I can create a new array but then I have the same problem from the start.
I'm really stuck on this and I would be very grateful for your help, thank you in advance.
Edit:
the objects array contains 4 objects.
You can create a Map of the objects using the zorder values as keys before sorting zorder.
Then Array#sort() zorder and Array#map sorted array returning the associated object from the Map object
let objects = [{id:100}, {id:300}, {id:400}, {id:200}],
zorder = [1, 3, 4, 2],
map = zorder.reduce((a, c, i) => a.set(c, objects[i]), new Map);
zorder.sort((a, b) => a - b);
objects = zorder.map(n => map.get(n));
console.log('zorder', zorder)
console.log('objects', objects)

Finding unique values in multiple arrays

I'm trying to solve a freeCodeCamp exercise with this goal:
Write a function that takes two or more arrays and returns a new array
of unique values in the order of the original provided arrays.
In other words, all values present from all arrays should be included
in their original order, but with no duplicates in the final array.
The unique numbers should be sorted by their original order, but the
final array should not be sorted in numerical order.
So what I do is concatenate all the arguments into a single array called everything. I then search the array for duplicates, then search the arguments for these duplicates and .splice() them out.
So far everything works as expected, but the last number of the last argument does not get removed and I can't really figure out why.
Can anybody please point out what I'm doing wrong? Please keep in mind that I'm trying to learn, so obvious things probably won't be obvious to me and need to be pointed out. Thanks in advance.
function unite(arr1, arr2, arr3) {
var everything = [];
//concat all arrays except the first one
for(var x = 0; x < arguments.length; x++) {
for(var y = 0; y < arguments[x].length; y++) {
everything.push(arguments[x][y]);
}
}
//function that returns duplicates
function returnUnique(arr) {
return arr.reduce(function(dupes, val, i) {
if (arr.indexOf(val) !== i && dupes.indexOf(val) === -1) {
dupes.push(val);
}
return dupes;
}, []);
}
//return duplicates
var dupes = returnUnique(everything);
//remove duplicates from all arguments except the first one
for(var n = 1; n < arguments.length; n++) {
for(var m = 0; m < dupes.length; m++) {
if(arguments[n].hasOwnProperty(dupes[m])) {
arguments[n].splice(arguments[n].indexOf(dupes[m]), 1);
}
}
}
//return concatenation of the reduced arguments
return arr1.concat(arr2).concat(arr3);
}
//this returns [1, 3, 2, 5, 4, 2]
unite([1, 3, 2], [5, 2, 1, 4], [2, 1]);
Looks like you overcomplicated it a bit ;)
function unite() {
return [].concat.apply([], arguments).filter(function(elem, index, self) {
return self.indexOf(elem) === index;
});
}
res = unite([1, 2, 3], [5, 2, 1, 4], [2, 1], [6, 7, 8]);
document.write('<pre>'+JSON.stringify(res));
Explanations
We split the problem into two steps:
combine arguments into one big array
remove non-unique elements from this big array
This part handles the first step:
[].concat.apply([], arguments)
The built-in method someArray.concat(array1, array2 etc) appends given arrays to the target. For example,
[1,2,3].concat([4,5],[6],[7,8]) == [1,2,3,4,5,6,7,8]
If our function had fixed arguments, we could call concat directly:
function unite(array1, array2, array3) {
var combined = [].concat(array1, array2, array3);
// or
var combined = array1.concat(array2, array3);
but as we don't know how many args we're going to receive, we have to use apply.
someFunction.apply(thisObject, [arg1, arg2, etc])
is the same as
thisObject.someFunction(arg1, arg2, etc)
so the above line
var combined = [].concat(array1, array2, array3);
can be written as
var combined = concat.apply([], [array1, array2, array3]);
or simply
var combined = concat.apply([], arguments);
where arguments is a special array-like object that contains all function arguments (actual parameters).
Actually, last two lines are not going to work, because concat isn't a plain function, it's a method of Array objects and therefore a member of Array.prototype structure. We have to tell the JS engine where to find concat. We can use Array.prototype directly:
var combined = Array.prototype.concat.apply([], arguments);
or create a new, unrelated, array object and pull concat from there:
var combined = [].concat.apply([], arguments);
This prototype method is slightly more efficient (since we're not creating a dummy object), but also more verbose.
Anyways, the first step is now complete. To eliminate duplicates, we use the following method:
combined.filter(function(elem, index) {
return combined.indexOf(elem) === index;
})
For explanations and alternatives see this post.
Finally, we get rid of the temporary variable (combined) and chain "combine" and "dedupe" calls together:
return [].concat.apply([], arguments).filter(function(elem, index, self) {
return self.indexOf(elem) === index;
});
using the 3rd argument ("this array") of filter because we don't have a variable anymore.
Simple, isn't it? ;) Let us know if you have questions.
Finally, a small exercise if you're interested:
Write combine and dedupe as separate functions. Create a function compose that takes two functions a and b and returns a new function that runs these functions in reverse order, so that compose(a,b)(argument) will be the same as b(a(argument)). Replace the above definition of unite with unite = compose(combine, dedupe) and make sure it works exactly the same.
You can also try this :
var Data = [[1, 2, 3], [5, 2, 1, 4], [2, 1], [6, 7, 8]]
var UniqueValues = []
for (var i = 0; i < Data.length; i++) {
 UniqueValues = [...new Set(UniqueValues.concat(Data[i]))]
}
console.log(UniqueValues)

Categories