Can someone explain to me what exactly is this line of code doing?
function findUniq(array) {
return array.find((item) => array.indexOf(item) === array.lastIndexOf(item))
}
I want to know what this line is exactly doing:
return array.find((item) => array.indexOf(item) === array.lastIndexOf(item))
What I think is happening here is that for every item inside the array it is comparing the first index of that item to the last index of item. it returns the items that equal to eachother.
I don't understand how it is returning the unique array.
If I were to write this function it would be like this:
return array.find((item) => array.indexOf(item) != array.lastIndexOf(item))
However, that doesn't work since it is returning the common number.
thanks
The Array.prototype.find() method takes a predicate function (a function that returns true or false based on input parameters) and then returns the element provided the predicate is true.
In your case, given the scenario:
var array1 = [1,2,1,3,5,2,3];
var array2 = [1,2,1,3,5,5,3];
function findUnique(array){
return array.find(
// The code below runs for every element of the array.
// - for each element, it takes the element and checks if first position, is the same as last position in the array
(item) => array.indexOf(item) === array.lastIndexOf(item) //
);
}
console.log("For array 1, unique item is: ",findUnique(array1));
console.log("For array 2, unique item is: ",findUnique(array2));
Array.prototype.indexOf(yourArrayElement) returns the position of the first occurrence of yourArrayElement
Oh the other hand, Array.prototype.lastIndexOf(yourArrayElement) returns the position of the last occurrence of yourArrayElement
If yourArrayElement only exists once within the array, the first and last position will be the same and Array.prototype.find() will return that element.
indexOf returns the first found position of the given element in the array whereas lastIndexOf returns the latest position of the given element in the array.
If indexOf === lastIndexOf, it means the first found element is the same as the latest one --> the element is unique in the array.
The reason that it return a unique number, because the find function loop from the start and from the end on each iteration, so if the index of both indexOf that loops from the start and lastIndexOf that loops from the end is equal it's mean that there are no duplicates across the array beside the current item.
This can be written two ways:
Match the first occurrence index with the final occurrence index.
const data = ['a', 'b', 'c', 'b', 'a'];
const findUniq = arr =>
arr.find((item) => arr.indexOf(item) === arr.lastIndexOf(item));
console.log(findUniq(data)); // 'c'
Check for an index of -1 for the next indexOf check.
const data = ['a', 'b', 'c', 'b', 'a'];
const findUniq = arr =>
arr.find((item) => arr.indexOf(item, arr.indexOf(item) + 1) === -1);
console.log(findUniq(data)); // 'c'
The first one is easier to read and convey, because it it written to compare the first and last index check. The second one is more obscure, but both work.
Related
I'm trying to find the 2nd largest number in an array, and square this number.
arr = [1,8,6,2,5,4,8,3,7] should return 49 (7 squared)
arr = [1,1] should return 1 (1 squared)
I've tried the code below and it works on the first array and return 49, but on the second array with [1,1] it returns NaN.
The problem is with the secondLargest variable--it returns undefined on the console.log. It may be because I'm using set, but I don't understand why it's not just returning 1 instead of undefined.
var maxArea = function(height) {
let secondLargest = Array.from([...new Set(height)]).sort((a,b) => b-a)[1]
console.log(secondLargest);
return Math.pow(secondLargest, 2);
};
Set eliminates duplicates, so the array [1, 1] gets turned into [1]. There is no second element, so you get undefined when trying to access index 1. Since this is not what you want, sort the array directly without creating a Set, or take the first element when there is no second element.
function maxArea(height) {
const sorted = [...new Set(height)].sort((a,b) => b-a);
return (sorted[1] ?? sorted[0]) ** 2;
}
console.log(maxArea([1, 1]));
console.log(maxArea([1,8,6,2,5,4,8,3,7]));
If I normally use for of loop and use iterator as entries that situation look like this:
var a = ['a', 'b', 'c'];
var iterator = a.entries();
for (let e of iterator) {
console.log(e);
}
// [0, 'a']
// [1, 'b']
// [2, 'c']
iterator: will be the entire array that contain all elements key/value pair. Key will be the index.
e: will be an element in the array
BUT what is this??????
let text = "A A A";
let splitwords = text.split(" ");
let words = [];
for (const [, item] of splitwords.entries()) {
words.push(item.split(""));
}
console.log(`This is the words: ${words}`);
what meaning the [, item] part???
and why should i use this pattern?
text.split("") do exactly same thing or not?
(Otherwise I try solve an text animation problem and this inherit from that code:
framer motion text animation )
Thank you
PS: I know this is an array destructing my main question that why????
for (const [, item] of splitwords.entries()) {
words.push(item.split(""));
}
[, item] is called array destructing, and the reason for that is because of entries in splitwords.entries(). The result of that array is like this [0, "a"],[1, "b"] (the first item is an index, and the second item is value), but in this case, they don't use an index, so the declaration is like [,item] (If they want to use it, the code can be [index, item]).
Without using an index, they can implement this way
for (const item of splitwords) { //remove entries and array destructing
words.push(item.split(""));
}
and why should I use this pattern?
Well, I think this is just their code style to use for of for collecting both index and value together. It depends on you need an index or not.
words.push(item.split("")) is different from the above case, they try to make the entire word "Hello" into characters ["H","e","l","l","o"] for the animation, so the final result of words can be
[
["F","r","a","m","e"],
["M","o","t","i","o","n"],
...
]
It's just a way to skip destructuring the first element in the array. You are basically saying that you are not interested in the first array item.
Since the entries() method returns a new Array Iterator object that contains the key/value pairs for each index in the array.
const foo = ['a', 'b', 'c'];
for (const [, item] of foo.entries()) {
// item would be 'a', 'b', 'c'
}
for (const [index, item] of foo.entries()) {
// item would be 'a', 'b', 'c'
// index would be 0, 1, 2
}
This is a destructuring assignment.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment
Array.prototype.entries() returns an array of 2 elements for the index and the item itself for each array item.
So in this expression the index is assign to nothing (because there is no variable declared before the comma) and the item is assigned to item.
Example
const ar = [1,2]
const [,value2]=ar
console.log(value2)
const [value1,]=ar
console.log(value1)
const [v1, v2] = ar
console.log(v1, v2)
For the item.split("") it just seems useless, the result would be the same in the present case with just words.push(item) since each word is just one letter... If the words were more than one letter this would just store each letter separately in the words array. Which could maybe be called letters I guess...
Edit:
for the "why use this pattern" question. In the present case, again it just seems useless. The index is not used so calling entries just don't seems relevant.
I don't know if you 'should' use this pattern, but if you want an explanation of what it is, it's like
for(let temp of splitwords.entries()){
const [, item] = temp;
words.push(item.split('');
}
And then const [, item] = temp; is basically the same as const item = temp[1].
Due to how ".entries()" work for an array (giving [index, value]), since the index is ignored by the destructuring, the resulting item is just the value. So, I don't think the result is any different from the following:
for (const item of splitwords) {
words.push(item.split(""));
}
Maybe they were preparing for the future, in case the index becomes important some day.
var check = [1,2,3,4,5,6];
var check1 =check.find((elements,index,array)=>{ return array ;}); console.log(check1);
Output is 1. Why? And if i want 3 as output from above array by giving checks or condition to the array argument then how to get it?
The find method executes the callbackFn function once for each index of the array until the callbackFn returns a truthy value. If so, find immediately returns the value of that element. Otherwise, find returns undefined.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find
And since you aren't really doing any checks and just returning c (a truthy value), which is the array itself, that's why it returns 1.
If you want to find 3 or any other value, you do the following (also name your function params better so it's easier to understand what is going on):
var check = [1, 2, 3, 4, 5, 6];
var check3 = check.find((element, index, array) => {
return element === 3
});
console.log(check3); // output : 3
In response to OP request in comments. The third parameter of the callback function passed into array.find can be used to modify the original array based on a condition. This example switches even values to the odd value 1.
const check = [1,2,3,4,5,6]
check.find((el, index, arr) => {
if (el % 2 === 0){
arr[index] = 1
}
})
console.log(check) // [2,2,3,4,5,6]
However, this is not the proper use of .find, and .find should not be used in this way. .find should be used to simply return the first value of an array that satisfies a condition, as decho explained in his answer. If you are wanting to update the values in an array consider using a for loop or .forEach.
Based on your comment here's how to check if a number exists at a particular index, and returning the number based on that check.
var check = [1, 2, 3, 4, 5, 6];
var check1 = check.find((el, i, arr) => {
return arr.indexOf(3) > 1 && el === 3;
});
var check2 = check.find((el, i, arr) => {
return arr.indexOf(3) > 3 && el === 3;
});
console.log(check1);
console.log(check2);
How to remove an element of an array and have that removed element saved in a variable:
var item = arr.remove(index)
You can use Array.prototype.splice for this purpose:
const arr = ['a', 'b', 'c'];
const removed = arr.splice(1, 1).pop();
console.log(arr) // ['a', 'c'];
console.log(removed) // 'b'
Note that in the example above, splice is chained with Array.prototype.pop - that's because splice, as mentioned by #Andreas, always returns an Array, so pop is used to extract the single value from Array returned by splice.
What you're looking for is splice. This takes as parameters the index of the item to remove, and the count of items from that to take out. Because you only want to remove 1 item, the 2nd parameter will always be 1. Splice also returns as an array, so we're indexing that [0] to get just the contents.
var arr = ['a','b','c'];
var item = arr.splice(1,1)[0]; // 'b'
Maybe something like this?
Array.prototype.remove=function(i){
var item=this[i]
this.splice(i,1)
return item
}
arr=[1,2,3]
item=arr.remove(1)
console.log(item) //2
console.log(arr) //[1,3]
I hope that this will help you!
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.