Confusion with how indexOf works in JS - javascript

I am new to JS and was trying to learn how to properly work with indexOf in JS, that is, if you look at the code below:
var sandwiches = ['turkey', 'ham', 'turkey', 'tuna', 'pb&j', 'ham', 'turkey', 'tuna'];
var deduped = sandwiches.filter(function (sandwich, index) {
return sandwiches.indexOf(sandwich) === index;
});
// Logs ["turkey", "ham", "tuna", "pb&j"]
console.log(deduped);
I am trying to remove duplicates but wanted to ask two questions. Firstly, in here return sandwiches.indexOf(sandwich) === index; why we need to use "== index;". Secondly, since indexOf returns index like 0, 1 or 2 ... then why when we console.log(deduped) we get array of names instead of array of indexes. Hope you got my points

You use a method of Javascript Array that is filter, this method take a function that returns a boolean.
The function filter returns a new Array based on the function passed applied to each entry.
If the function return true, then the entry is included in the new Array, otherwise is discarded.
As the functions check the indexOf an entry to be the current index is true for the first occurrency of the entry.
All the duplications will fail the expression as they are not the first index found by indexOf, so they are discarded.

since the logic is to remove the duplicates from the array,
in your example, you have "turkey" as duplicates.
the "turkey" exists in position 0,2,6
so whenever you call indexOf("turkey") always returns 0 because the indexOf function returns the first occurrence of a substring.
so for the elements in position 2 & 6 the condition fails. then it won't return that element.
That is how the filter works in javascript. it evaluates the condition and returns true or false that indicates whether an element to be included in the new array or not, in your example the condition is return sandwiches.indexOf(sandwich) === index;

Perhaps the basic logic is easier to see at a glance if you use arrow notation:
const deduped = myArray => myArray.filter((x, i) => myArray.indexOf(x) === i);
The key point is that indexOf returns the index of the first occurrence of x. For that occurrence the result of the comparison will be true hence the element will be retained by the filter. For any subsequent occurrence the comparison will be false and the filter will reject it.

Difference between === (identity) and == (equality): if type of compared values are different then === will return false, while == will try to convert values to the same type. So, in cases where you compare some values with known types it is better to use ===. (http://www.c-point.com/javascript_tutorial/jsgrpComparison.htm)
You get as result an array of names instead of array of indexes because Array.filter do not change the values, but only filter them. The filter function in your case is return sandwiches.indexOf(sandwich) === index; which return true or false. If you want get the indexes of your items after deduplication, then use map after filter:
a.filter(...).map(function(item, idx) {return idx;})

#Dikens, indexOf gives the index of the element if found. And if the element is not found then it returns -1.
In your case you are filtering the array and storing the values in the deduped. That's why it is showing an array.
If you console the indexOf in the filter function then it will log the index of the element.
For example :
var deduped = sandwiches.filter(function (sandwich, index) {
console.log(sandwiches.indexOf(sandwich));
return sandwiches.indexOf(sandwich) === index;
});

Related

how to remove an object within an array using the object's index

so I created an array with several objects inside it
const students = [
{jean:14},
{mike:19},
{nean:16},
{annie:17}
]
and I want to remove certain object from the array by using the object's index
let index = students.findIndex(i => {
if (Object.keys(i) == 'nean'){
return true
}
})
and it returns the index of the object that I want to remove from the array and I do .splice() to remove it from the array. It does remove the object that I expect to be removed but it also removes the item after it
students.splice(index, index)
console.log(students)
//(2) […] 0: Object { jean: 14 } 1: Object { mike: 19 } length: 2
When using splice, the first argument is the index and the second is how many elements to remove from that index. so in order to remove just that element, you can do: students.splice(index, 1)
reference: splice
Array.splice() should be provided at least 2 arguments and from argument 3 to infinity are optional,
the first argument is the index where u want to start your manipulation,
the second argument is the number of items that you would like to be deleted from that index onwards,
and the third argument is the string/object that you would like to add
in your example you would like to start at the index that you have found using this function:
let index = students.findIndex(i => {
if (Object.keys(i) == 'nean'){
return true
}
})
and you would like to delete just one! so you need to provide 1 for the second argument and not index,
js students.splice(index, 1)
as you don't need to add anything you will not provide the 3rd argument,
I hope this helps with all your array splice needs,
good luck

Unable to understand the indexOf in javascript in order to find Unique Value in String?

I have below code to check the string is unique or not.
function unique(str) {
let values = [];
for (let letter of str) {
if (values.indexOf(letter) !== -1) {
return false;
}
values.push(letter);
}
return true;
}
console.log(unique("abbds"));
I don't understand the if condition inside properly. Can anyone make me understand this concept?
Here is what your code is doing.
You have string abbds and an array values. In the first iteration
You check the first character a inside values
values.indexOf("a") which results in -1 because a is not present in values.
In this case, values.indexOf("a") since a is not inside values you push it inside values.
If the values has the character in which case the indexOf will return the index of the first occurrence of the item.
And thus values.indexOf(letter) !== -1 will be `true.
The indexOf() method returns the first index at which a given element can be found in the array, or -1 if it is not present.
From MDN : Array.prototype.indexOf()

How to code a function that checks if an array contains a number by returning a boolean

I just started learning code and i'm currently stuck on the following assignment.
Assignment:
Code a function that checks if an array contains a number by returning a boolean.(Java code)
Examples: contains([1, 2, 3, 4], 3) returns true. contains([2, 2, 4], 3) returns false.
I've tried the following:
code
Can anyone help me with solving this one?
You can use the includes() method which is available for JavaScript arrays. It will check if a specific element is included in the array and will return a boolean value of either true or false.
function contains(array, number){
var ans = array.includes(number);
return ans;
}
console.log(contains([1,2,3,4],3)); // Prints true
console.log(contains([2,2,4],3)); // Prints false
You should iterate for each array element. Considering that your array contains numbers check the following function
function contains(numberArray, check){
var i;
for (i = 0; i < numberArray.length; i++) {
if (numberArray[i] == check){
return true;
}
}
return false;
}
It takes the numberArray array as input and the check number. Then it iterates for each number in the array and checks if it finds the same number with the check number.
If it finds it, then it returns true and the loop breaks.
If it does not find it, after the loop is finished iterating all the elements of the array, then it returns false.
An array is a collection of elements of a specific type. Your function takes two parameters: the array in which you want to search, and the number you want to search.
To achieve this, you have to iterate through the array, using a controlled iteration like a for loop. The loop takes all elements in the array one by one, and performs an action that you define in the loop body, in your case you can compare the current array element to the one passed to your function. If they are the same, you can return from the loop using the return statement. If all elements were
Assuming that you're using JavaScript, you'd do something like this using the for statement:
function contains(array, number){
for(var currentElementIndex in array) {
if(array[currentElementIndex] === number) {
return true;
}
}
return false;
}

In underscore.js/lodash.js, how to remove duplicate tuple using `uniq`?

Here is the expression
_([1,2],[1,3],[1,2]).uniq().value()
The evaluated value is
[[1,2],[1,3],[1,2]]
Though what I expect is [[1,2],[1,3]]..
Does anyone have ideas about this?
Underscore uses strict equality on the list if you don't supply a predicate. So in your example underscore will be checking that a value is in the result array by comparing 2 arrays e.g. [1,2] === [1,2] which will always be false as they are two different arrays.
One quick 'n' dirty solution would be:
var result = _.uniq(data, function (a) {
return a.join(',');
});
If you want to compare uniqueness using isEqual(), which is a fairly versatile approach, I would do something like this:
_.reduce(coll, function(result, item) {
if (!_.any(result, _.ary(_.partial(_.isEqual, item), 1))) {
result.push(item);
}
return result;
}, []);
Using reduce(), you start off with an empty array. Then any() tells you if the current item is already in the results array. If not, it adds it.
Using toString() to compare compare complex values can lead to inconsistencies. However, most of the time it's sufficient - use this approach if you end up with unexpected results.

Using indexOf to remove an Object from a list?

So, I have seen this piece of code:
removeOrder = (order) ->
index = listOfOrders.indexOf(order)
if index isnt -1
listOfOrders.splice index, 1
where order is an object like this:
order = {
id: whatever
field1: whatever
...
}
This is working now because the order that is passed as argument is referencing some object in listOfOrders, something like removeOrder(listOfOrders[i]). But my question is, is this safe? I mean, I think it would be better to iterate over the list of orders and search for an object with the same id, for example, and remove it.
As far as I know indexOf is Ok when the object we are searching for is a "simple" object (a number, a string, etc.).
According to These docs for indexOf, indexOf uses strict equality ===.
var a = {id:1};
var b = {id:1};
a === a; // this is true
a === b; // this is false
So its safe to in general for objects
You do need to check that indexOf != -1 before the splice though
var removeOrder = function(order)
{
var index = listOfOrders.indexOf(order);
if (index != -1)
return listOfOrders.splice(index, 1); //for chaining?
return listOfOrders;
}
It's safe to use indexOf if the intended purpose is to remove an object from the array by it's reference.
If you want to remove first object by id let's say, you would use something like:
var removeOrderById = function(orderId)
{
var orders = listOfOrders.filter(function(item)
{
return item.id == orderId;
});
if (orders.length > 0)
{
var index = listOfOrders.indexOf(orders[0]);
return listOfOrders.splice(index, 1); //for chaining?
}
return listOfOrders;
}
Conclusion: it's all about the use case.
The function works as inteded assuming that there is exactly one reference to the object in the array.
If the object isn't in the array (or you are calling it with a clone of an object in the array), the index will be -1 and the splice call will remove the last item in the array instead. As this is not a reasonable behaviour, there should really be a check for that (which I see that you added).
The indexOf method works reliably for object references, but it natually has to be looking for the same object.
Looking for an object with a specific propery value would also work, but it goes with the same assumptions; the value has to occur exactly once in the array to work as intended.

Categories

Resources