javascript: How to compare two arrays of objects using functional programming? - javascript

So recently I was doing a node school challenge,
Here's the task:
Return a function that takes a list of valid users, and returns a function that returns true
if all of the supplied users exist in the original list of users.
Here's the solution:
module.exports = function (goodUsers) {
return function (submittedUsers) {
return submittedUsers.every(function (submittedUser) {
return goodUsers.some(function (goodUser) {
return goodUser.id === submittedUser.id;
});
});
};
};
Basically its a function that takes in an object of ids and compares it with another one.
it returns true if if the second objects' ids are in the first object.
Here's an example: http://s8.postimg.org/ql8df5iat/Screen_Shot_2014_02_01_at_5_32_07_PM.png
However I've read the MDN examples for awhile and just can't seem to understand why this solution works! Can someone walk me through step by step on what's actually happening here? Why does this work? How do the every() and some() methods handle the differences is array length? etc
-Thanks

Actually the functions every and some don’t care about array length.
every will just execute an arbitrary code for each element of your first array.
some will just return true if there is at least one object with the same id' in the second array.
Note === this will "short circuit" in the case of null or undefined values.
Hope this helps.
Personally, I prefer the double “for” loop syntax as I think it is more readable.

Related

Best way to set variables from an array of objects

I have the following code which feels a bit redundant as I'm iterating over the same array many times, any suggestions to improve while keeping it readable would be appreciated.
The array object format is a standard one where I am checking the keys in each object to check it matches a certain condition e.g. every object contains one value, or only some of them do e.t.c [{},{},{}]
const getValue = arrayOfObjects => {
const hasA = arrayOfObjects.some(
object => arrayOfObjects.abc === 'val1'
);
const hasB = arrayOfObjects.every(
object => arrayOfObjects.abc === 'val2'
);
// the above 2 iterations are repeated about 4 more times for different checks
// then there are a few versions of the below assignment depending on the above variables
const hasC =
hasA ||
hasB;
// finally the function returns one of the values
if (hasA) {
return 'val10';
} else if (hasB) {
return 'val11';
} else if (hasD) {
return 'val12';
}
};
This sounds like a theoretical question. It sounds like you're wondering if using a few Array.prototype methods like some and every on the same array over and over has downsides or if there is a more readable way to do it.
It depends.
If the size of the array n is generally pretty small, in a practical sense, it doesn't matter. Choose what is more readable. Big O complexity comes more into play on a practical level if you're dealing with a lot of array items.
Boolean vars derived from some and every can be very readable in my opinion.
If you are in a situation where the array could be quite large, you could consider trying to do it in one step. Array.prototype.reduce would be a good tool for this: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce
In general when you're making use of every and some (which I personally love, as they're very readable), you should stop and think about the necessity of the checks you're making.
To simplify the examples you had, let's say you have a bunch of fruits and you're checking whether:
There is at least one orange.
All of the fruits are apples.
It's clear that
If (1) is true, then (2) must be false
And the other way around:
If (2) is true, then (1) must be false
Then you can spare the testing one of them if the other one is true, using else if for example.
Additionally, if one of them is false - then you simply don't have to check (1) or (2), which is guaranteed to be false.

Array .filter and .map OR .map with a if condition

Recently I was doing some sort of filter to an array and I came up with two cases and I don't know which one to use.
In terms of performance, which is better to use.
arr.filter(someCondition).map(x => x.something)
Or
arr.map(x => {
if(someCondition) {
return x.something
}
})
One thing to notice is that I'm using react, so have undefined values in the returning array (don't return any thing inside .map), it's totally acceptable.
This involves a lot of questions like, how many elements you have in the array and how many you of then will pass the condition and that is what make be wonder which one is better.
So, considering n elements and cases where all elements pass the condition and also that no elements pass the condition, which one have better performance?
.filter().map() OR .map with if inside?
First: It's really unlikely to matter.
But: Only because it's okay in your case to have undefined in the result array, the second one will be faster.
Let's compare:
The first way, filter has to make a pass through the entire array, creating a new array with the accepted entries, then map has to make a pass through the new array and make a new array of the something properties.
The second way, map makes one pass through the array, creating a new array with the something properties (or undefined for the ones that would have been filtered out).
Of course, this assumes you aren't just offloading the burden elsewhere (e.g., if React has to do something to ignore those undefineds).
But again: It's unlikely to matter.
I would probably use a third option: Build the result array yourself:
const result = [];
for (const x of arr) {
if(someCondition) {
result[result.length] = x.something;
}
}
That still makes just one pass, but doesn't produce an array with undefined in it. (You can also shoehorn that into a reduce, but it doesn't buy you anything but complexity.)
(Don't worry about for-of requiring an iterator. It gets optimized away in "hot" code.)
You could use reduce function instead of map and filter and it wouldn't return you undefined like when you use map and if.
arr.reduce((acc, x) => (someCondition ? [...acc, x.something] : acc), [])
or
arr.reduce((acc, x) => {
if (someCondition) {
acc.push(x.something);
return acc;
} else return acc;
}, []);
As #briosheje said smaller array would be a plus. As it reduces number of rerendering in your React app where you use this array and it is unnecessary to pass undefined. Reduce function would be much more efficient, I would say.
If you are wondering why I have written 1st one using spread operator and 2nd one without it is because the execution time taken for 1st one is more compared to 2nd one. And that is due to spread operator as it is cloning 'acc'. So if you want lesser execution time go for 2nd one or else if you want lesser LOC go for 1st one

How to check if there is at least one element in a multidimensional array? (Silly Basic Javascript Questionn)

How to check if there is at least one element in an array? (I want to verify if the array is not empty.)
Sorry for this silly question, I already spent too much time on Google... (Google only returns complex situations and solutions. It seems like my question is too simple.).
EDIT: Ok, but what will happen with an array like [,,[],,[],,,] ? For my purposes, it should be considered as empty.
EDIT 2: Sorry, guys, for the confusion! At first, I didn't even know exactly what I was looking for. Thank you all!
This would fulfill your new requirements:
function isEmpty(arr) {
if (!Array.isArray(arr)) {
return false;
}
return arr.every(isEmpty);
}
What it does: with the help of Array.prototype.every it checks that the every item left is an empty array. And the array holes are automatically skipped by .every().
References:
Array.isArray()
Array.prototype.every()
You could also use truthiness here. This would help you check against undefined at the same time. [] is falsy, so you could do this:
var arr = [];
if(!arr) {
... arr is undefined or empty array
} else {
... arr has at least one value
}

What's the first argument of Array.apply in JavaScript?

In an answer, #Tushar suggested the syntax corresponding to the following.
Array.apply(null, Array(3).fill(10))
.map(function (item, index) {
return item + index;
});
I do understand what's going on here and I'm satisfied. However, it bugs me a bit that there's this null valued argument doing seemingly nothing. So I went off and started researching. According to the wisdom on the web, it's a reference to this. Now, that gave me very little clarity and despite of putting in cucumbers, arrays, and objects into that, it didn't affect jack, as far I could tell. In fact, I'm curious why the following wouldn't be equivalent, let alone suffice.
Array(3).fill(10)
.map(function (item, index) {
return item + index;
});
Further on, I read something about Cr an IE not accepting array-like objects, which tells me even less. Also, it's a bit hard to verify the age of the article so the validity of its claim's hard to assess. I got as far as to the talk about prototype constructors and gave up, not being sure if I'm on the right path.
The first argument of apply is only important if you're using a function that uses this.
Running the following snippet should make it a little clearer:
var o = {value: 1};
var fn = function(a) {
console.log(a + this.value);
}
value = "something else";
fn("an argument ");
fn.apply(o, [20]);
// the above prints:
// an argument something else
// 21
https://jsfiddle.net/f2zw8edd/
Array(number) creates an array of the given size, however it does not populate any of its data points. Calling map or fill or pretty much anything else on it therefore won't do anything useful.
Array(item1, item2, item...) on the other hand creates an array with the given items as elements of the array. You can call map, fill, whatever you want on this and it will work.
So how can you use this to create an array of a given size that you can call map on? Exactly the way you see.
What Array.apply(null,Array(3)) does is create an unpopulated array of size 3, then passes those 3 undefined items as arguments to Array, thus resulting in
Array(undefined,undefined,undefined), which gives you a mappable array. It's important to note that you're creating two arrays here, but the Array(3) is discarded after use.
So why null? That would be because when creating an array, there is no place where this is relevant. Since the context is irrelevant, you can pass literally anything you want as the context and it will run just fine, but it's easiest to understand that context doesn't matter if you pass it null.

Need help understanding lodash's _.includes method

I would like to use lodash's _.includes method in my code, but any time I have an array of objects I can't get it to work, and instead end up relying on the _.find method.
From my tests I can only get _.includes to work with simply arrays. But maybe that's the way it's supposed to work?
I am very new to Lodash and programming in general, so I thought I would ask in case I am missing something about how I can use this method.
I created a jsbin with the following code: http://jsbin.com/regojupiro/2/
var myArray = [];
function createArray(attName, attId, otherId) {
var theObject = {};
theObject.attributeName = attName;
theObject.attributeId = attId;
theObject.otherId = [otherId];
return theObject;
}
myArray.push(createArray('first', 1001, 301));
myArray.push(createArray('second', 1002, 302));
myArray.push(createArray('third', 1003, 303));
myArray.push(createArray('fourth', 1004, 304));
var isPresent1 = _.includes(myArray, {'attribtueId' : 1001});
var isPresent2 = _.includes(myArray, 1001);
var found = _.find(myArray, {'attributeId' : 1001});
console.log(isPresent1);
console.log(isPresent2);
console.log(found);
console.log(myArray);
Both "isPresent" variables return false, but the _.find method returns the correct object.
I would love some help in better understanding how I could use the _.includes method when I just need to do a simple true/false check to see if a value is present in my array of objects.
Or, if this is the wrong tool for the job, is the _.find method the right tool for this job, or some other lodash method that I'm not familiar with yet?
Thank you for your help!
I think some() does exactly what you're looking for.
The _.includes() method compares with the SameValueZero comparator, which is a special comparison mostly like ===. Even if you have an object in your array that looks like {'attribtueId' : 1001} that _.includes() call will never find it because two distinct objects will never compare as === to each other.
When you pass an object to _.find(), by contrast, the library assumes that you want it to carry out an _.matches() comparison, which will compare properties of the "target" object. Thus, in your case, _.find() is probably the right choice. The _.includes method really fills a distinct niche.

Categories