Difference of Two Arrays - javascript

I have a quick question about finding the difference between two arrays. I found a chunk of JavaScript code that does what I want here and modified it a bit:
JS
function diffArray(arr1, arr2) {
var newArr = [];
var myArr = arr1.concat(arr2);
newArr = myArr.filter(function(item){
return arr2.indexOf(item) < 0 || arr1.indexOf(item) < 0;
});
return newArr;
}
diffArray([1, 2, 3, 5], [1, 2, 3, 4, 5]);
However, I'm not sure that I really understand what the filter function is doing here. Could anyone give me a clear explanation of how this works.
Note: I already know the basics of filter functions. I'm looking for a specfic explanation of this filter.

newArr = myArr.filter(function(item){
return arr2.indexOf(item) < 0 || arr1.indexOf(item) < 0;
});
The Array#filter function iterates over each element of the newly made array from concat function (containing every element from arr1 and arr2 arrays).
If at least one of the conditions arr2.indexOf(item) < 0 or arr1.indexOf(item) < 0 is fulfilled (returns true) at some iteration, the Array#filter function filters out (returns) that specified (actually iterated) element.
In case, if the iterated element is both in arr1 and arr2, the indexOf function will return it's index (which is higher than 0) - the condition will return false (it's not smaller than 0). We will receive then false || false which is false and that element won't be included in the newArr array, containing unique elements.
In case, if given element is only in one array (it doesn't exist in the second one - it's index will return -1 - it will fulfill the < 0 condition) - one of the conditions will return true, so the both conditions will become true || false which is true - given element will be included in the newArr array.

Filter is using a lambda to filter the list.
This essentially means that it executes the code between the { } and returns an array that meets the criteria. Your criteria are that the index of the item is greater than 0 in both arrays which is essentially just saying it's in both arrays.
you can read more here: https://www.w3schools.com/jsref/jsref_filter.asp

Easy way of thinking this is that filter function is internally creating an array.
The elements of this internal array are the ones that pass the condition in the callback function. This is possible since this decision is being made one element at a time in the callback function.
Condition arr2.indexOf(item) < 0 || arr1.indexOf(item) < 0 passes only for element 4 since at that time 4 is not present inside arr1. Since true is returned element 4 is added in the internal array. Ultimately 4 is returned in newArr.

Related

map function to return 1 boolean value, instead of an array of boolean values

Say you have an array like this:
arrayExample = [1, 2, 3, 4, 5, 6, 7]
I want to use the map function to iterate through arrayExample and return true if all the numbers are less than 8, false if they are not. However, when I do this I get an array of trues (like: [true, true, true... etc])
Would I be able to return just 1 value?
Here is my code so far:
var testBoolean = true;
var array = [1,2,3,4,5,6,7];
testBoolean = array.map(m => {
//if a number in the array is >=8, changes the testBoolean to false and return false only
if(m >= 8)
{
return false;
}
//VS code said I had to have a return here, I believe its because I need to have in case m < 8 (edited after reading a comment)
return true;
})
//prints an array [true,true,true,true,true,true,true]
document.write(testBoolean);
I'm a bit new to "map" but I believe it does this since it returns a value for every element, just confused on how to make it so it returns 1 true or false.
The simplest solution is to use .some().
We don't need to check every value. We need to find the first value not less than 8.
const array = [1, 2, 3, 4, 5, 6, 7]
const testBoolean = !array.some(m => m >= 8)
console.log(testBoolean)
For something like this .map() isn't the right tool. .map() is for converting all the elements in your array to new elements (ie: mapping each element to a new transformed value). As a result, .map() will always return an array (unless this behaviour is intentionally modified). Instead, you can use .every() for this, which will tell you if all elements in your array match your condition (ie: if your function returns true for every element, then you'll get true as your result, otherwise you'll get false). The .every() method will terminate early as soon as it finds one element which your callback function returns false for, which can help with efficiency:
const array = [1, 2, 3, 4, 5, 6, 7];
const testBoolean = array.every(m => {
if (m >= 8) {
return false;
}
return true;
});
console.log(testBoolean);
This can be written more concisely, by just returning the result of m < 8 (this will either evaluate to true or false)
const array = [1,2,3,4,5,6,7];
const testBoolean = array.every(m => m < 8);
console.log(testBoolean);
From a more general perspective, if you want to return a single value from an Array, .reduce() is your friend.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce
Specifically in your case, you could do
array.reduce(function(accumulator, currentVal, i, arr) {
return accumulator && currentVal < 8;
}, true));
So .reduce() iterates through your array with an initial value true and returns the "previous" value (accumulator) AND whether the current value is less than 8.
You could think of it as
(true && (a[0] < 8 && (a[1] < 8 ... )))
The returned value at each iteration becomes the accumulator of the next. In this way you could not only do math operations but also change an array of a certain shape (e.g. array of {w:0, h:0} objects) to an output of another (e.g. a single number being the sum of all the hypotenuses calculated from each w and h).

Finding an item's index in an array

I was writing a function that takes two arguments, an array and a number, and returns the index of the number if it's present in the array. The issue I encounter is the fact that my code returns properly without the "else" part, however, when I add the code about returning "-1" it doesn't work properly and it seems as if the compiler only takes "return -1" into account, no matter what arguments I use. Could anyone help me solve this issue?
function search(arr, item) {
for(let i=0; i<arr.length; i++){
if(item===arr[i]){
return i;
}else if(item!==arr[i]){
return -1;
}
}
}
It's always giving me an output of "-1", when it's supposed to give the index of the "item" argument if it's presents in the first array argument.
You need return -1 outside the loop so it only returns -1 if it makes it all the way through the loop without finding something. If it finds something before that, it will return the index:
function search(arr, item) {
for(let i=0; i<arr.length; i++){
if(item===arr[i]){
return i;
}
}
return -1;
}
console.log(search([1, 2, 3], 5))
console.log(search([1, 2, 3], 2))
Think about this sequentially.
Let's say your array is [1, 2, 3] and you're looking for 3.
The function loops over the array. The first value considered is 1. That actives the else block and returns -1 before the other values are even considered. Remember return means end of function execution.
In any case, you can greatly simplify the function:
return arr.indexOf(item);

Empty elements in JS array declaration

it's my first question here, after have been reading for years, so be nice with me please.
I'm having trouble with array management in js/jq.
I have array with several elements, which is processed with $.each function.
I want to extract matching elements to another array and return this array.
But for some reason (don't know if it's because array declaration, jquery.each function...) I'm having first empty element.
I think I'm making this more difficult to understand than it's, so made jsfiddle.
var arr = new Array();
$.each([1,2,3], function(index,element){
if (element == 2){
arr[index] = element;
}
});
arr must have only 1 element, but arr.length returns 2 because first array slot is empty.
Here is a fiddle http://jsfiddle.net/moay7y95/
I'm so sure that it's a simple and little stupid thing, but I've not been able to find an answer.
Thanks in advance!
You are pushing an element in array at 1st index. So, javascript by default put undefined at 0th index.
So, at the end of each your array will be
[undefined, 2];
This is the reason you get the length as 2.
You can use push to add element in array:
$.each([1, 2, 3], function (index, element) {
if (element == 2) {
arr.push(element);
elem++;
}
});
Demo: https://jsfiddle.net/tusharj/moay7y95/2/
The push() method adds one or more elements to the end of an array and returns the new length of the array.
Docs: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/push
Best solution: Use .filter
var arr = [1, 2, 3].filter(function(value){
return value == 2
});
If the return value is true, the element is included in the returned array, otherwise it is ignored. This is pure js, so you don't need jquery. See documentation about .filter
Your problem: Use .push
Try using the .push method on the array (see Mozilla's documentation).
var arr = new Array();
$.each([1,2,3], function(index,element){
if (element == 2){
arr.push(element);
}
});
The .push method will dynamically grow your array as elements are added.
Your problem is that the value of index inside your function is a reference point in your initial array. This means that if you look at the returned array, you will find [undefined, 2] and so the length is returning as 2. If your condition were element == 3 you would have two empty slots.
Alternatively: Use .grep
Another jQuery method is $.grep. See http://api.jquery.com/jquery.grep/
var arr = $.grep([1, 2, 3], function (value) {
return value == 2
});
This is jQuery's implementation of javascript's .filter.
Your array [1, 2, 3] has three elements, and three associated indexes: 0, 1 and 2. In each iteration of your $.each() loop over that array, the index and its value get passed to the function.
So the first call gets 0, 1 passed as its arguments. The second call gets 1, 2 passed as its arguments, then the if statement condition evaluates to true, so your code:
arr[index] = element;
is actually equivalent to
arr[1] = 2;
Since you're inserting an element at index 1, you'll end up with an empty index 0.
You could instead simply use Array.push() to add the element to the array:
arr.push(element);
As already mentioned the problem is you are assigning the value at index 1, so the array will be considered of length 2.
One solution is to use .push() instead of assigning based on index.
Another approach could be is to use Array.filter() and return true if the element matches the conditon
var arr = [1, 2, 3].filter(function(value){
return value == 2
});
Demo: Fiddle
Using $.grep()
var arr = $.grep([1, 2, 3], function (value) {
return value == 2
});
[1, 2, 3]
if (element == 2)
arr[index] = element;
This means you're setting arr[1] to element.
If you want to add it to the arr sequentially (filling it up normally), push it into art
arr.push(element);
Seems like you're looking for Array.filter (MDN).
var elems = ["car", "bike"];
var arr = [1, 2, 3, "car", 5, "bike"].filter(myFilterFunc);
function myFilterFunc(val) {
if (elems.indexOf(val) > -1) return true;
}
Fiddle

Javascript Arrays - Find Duplicates [duplicate]

This question already has answers here:
Get all non-unique values (i.e.: duplicate/more than one occurrence) in an array
(97 answers)
Closed 8 years ago.
Here is my question...
Given an array populated with numbers as a function parameter, produce a resulting array which contains any duplicates number from the array.
For example, given the array [ 1, 2, 4, 4, 3, 3, 1, 5, 3 ] it should return [1, 4, 3]. For extra bonus points return a sorted array.
I am starting out with Javascript - I know the language however, using it in the correct way ( as one should ) I'm still getting to grips with.
My pseudo code for this would be to:
Create an array with the numbers above var numbers = [1, 2, 4, 4, 3, 3, 1, 5, 3];
Then create an empty array named "result" var result = [];
Create a for loop that goes through the var numbers to check for duplicates which will then populate the empty array "result" with the duplicates
for (var i = 0;i < numbers.length; i++) {
//This is where I'm stuck...
}
I'm not sure what to do within the for loop to populate the var result and to throw in to the mix... The given array has to be a function parameter which makes sense so you can change the numbers in one place.
Any feedback on my thought process on this so far is greatly appreciated but ultimately I am wanting to learn how to achieve this.
Here is a JSFiddle of my progress so far... http://jsfiddle.net/fbauW/
One way of doing this (and it's not the only way) is by checking for existing elements in the array. Take a look at JavaScript's lastIndexOf function:
http://www.w3schools.com/jsref/jsref_lastindexof_array.asp
It will return -1 if the object does not exist in your array, and if it exists, will return an index of a later position than you are in. So you can use an if statement in your loop that checks whether or not there is another index containing your number, and add it in to your results array IF AND ONLY IF the index you get back != the index you are currently on (if they equal, this means that there is only one of that element in the list).
If you need more help, comment here and I can type some code in!
Good luck!
Array.prototype.contains = function(k) {
for ( var p in this)
if (this[p] === k)
return true;
return false;
};
//this prototype function checks if an element is already in the array or not
//go through all the array and push the element to result if it is not
//this way we can eliminate duplicates
//result will contain the resultant array
function findDuplicates(Numbers) {
var arrayLength = Numbers.length, i, j, result = [];
for (i = 0; i < arrayLength; i++) {
for (j = 0; j < arrayLength; j++) {
if (a[i] == a[j] && i != j && !result.contains(a[i])) {
result.push(a[i]);
}
}
}
return result;
}

Zepto's use of array.filter

I am trying to boost my Javascript understanding, so I've been looking through the Zepto library. I came across this line:
uniq = function(array){
return array.filter(function(item, idx){
return array.indexOf(item) == idx
})
}
What is the purpose of this function? From what I can tell, it is creating a new, unique array of elements, right? But isn't it essentially just cloning the array? If so, wouldn't array.slice() be faster?
Finally, wouldn't it increase performance to change array.indexOf(item) to array.indexOf(item,idx)? Or better yet, just return true? When does array.indexOf(item)==idx not equal true? Is this to prevent duplicate items? But when would that ever actually happen?
it is creating a new, unique array of elements, right?
It just filter your array elements to return unique elements.
demo
But isn't it essentially just cloning the array?
No as I explain above.
If so, wouldn't array.slice() be faster?
Slice doesn't remove duplicates.
Finally, wouldn't it increase performance to change array.indexOf(item) to array.indexOf(item,idx)? Or better yet, just return true?
If you only return true you won't identify if the element is duplicated or not.
demo
When does array.indexOf(item)==idx not equal true?
Example:
I have the following array:
['10', '20', '30', '20', '10']
Iterations:
1: array.IndexOf(10) == 0 ? // yes, so return true
2: array.IndexOf(20) == 1 ? // yes, so return true
3: array.IndexOf(30) == 2 ? // yes, so return true
4: array.IndexOf(20) == 3 ? // no because array.indexOf(20) is 1 , so return false
5: array.IndexOf(10) == 4 ? // no because array.indexOf(10) is 2 , so return false
So, when the element has already been found it gets false because the indexes are not the same.
It seems that this code is eliminating duplicates.
Ahh I see the "difference" we're questioning. You kinda answered it though, in your edit. I think this method returns a new array that contains unique values from the original.
When the indexOf method scans the array, it finds the first occurrence of the currently inspected item. If that occurrence is not the same index as the current index being inspected, the indexOf result will not equal idx. Therefore, it will not return the value because it either wasn't found, or it was found earlier in the array (which means it's a duplicate).
Here's an example:
[10, 30, 10, 100]
When the filter methods goes through the items: 10, 30, 10, then 100, it will perform the indexOf on it.
For 10, indexOf will return 0. And idx is also 0.
For 30, indexOf will return 1. And idx is also 1.
For 10, indexOf will return 0. But idx will be 2.
For 100, indexOf will return 3. And idx is also 3.
Therefore, [10, 30, 100] will be returned, not just a simple clone of the original.
The function (as named) takes unique items in the original array, and returns them in a new array. So if the original array has distinct items, it will just return a clone.
Remember, indexOf returns the first index of a given item. So if the current item appears twice in the array, the filter value will be false.
For example.
var a = [1, 2, 3];
var b = [1, 2, 3, 2];
console.log(uniq(a)); // [1,2,3]
console.log(uniq(b)); // [1,2,3]
​
As others have said already this gets rid of duplicates in an array. Just added my answer to show why this works. If you log out the values inside the filter function you'll see the pattern:
array.filter(function( item, idx ){
console.log( item, idx, array.indexOf( item ) );
...
...
console.log( uniq( ['a','a','b','b','c','c','c','d'] ) );
/*
a 0 0 *
a 1 0
b 2 2 *
b 3 2
c 4 4 *
c 5 4
c 6 4
d 7 7 *
*/
Check the last column, that's what determines if the item already exists so the comparison array.indexOf(item) == idx checks against the second column, if it's not the same number it is a duplicate. For the item to be unique (*) the index and the index position must match.

Categories

Resources