Using indexOf to remove an Object from a list? - javascript

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.

Related

Sparse Array HackerRank Exercise

I'm trying to resolve some exercises from hacker rank, and I'm struggling with the array map and filter methods.
This function supposes to search a value from queries array into strings array and when I use the map method it returns an array with undefined values, and when I use the filter method it returns an empty array.
var strings = ['ab','ab','bca','acb']
var queries = ['ab','abc','bc']
function matchingStrings(strings, queries) {
let retArr = []
for(let n = 0; n<queries.length; n++){
var equalelem = strings.filter(function(queries){queries[n] === [...strings]})
retArr.push(equalelem.length);
}
return equalelem
}
console.log(matchingStrings(strings, queries))
Looking only at your syntax, and without analyzing the algorithm, the following things should change:
Your filter function always returns undefined. Any function that doesn't have an explicit return statement returns undefined. Maybe you wanted to use an arrow function expression, which doesn't require a return statement if you omit the curly braces?
var equalelem = strings.filter((queries) => queries[n] === [...strings])
Inside the filter function, you seem to be comparing an element from list queries to a copy of list strings. Comparing an element of a list (in this case, a single string) to a list will never be true in your case.
The variable letArr doesn't seem to serve any purpose.

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()

Confusion with how indexOf works in JS

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;
});

Filter array of objects based on property value regardless of case using Underscore?

I have a list of objects which have a last name property and I would like to find the object with the last name which the user types in.
I can do this using the underscore filter function which works fine but the case matters. So for example if the last name is Jacobs in my object array and the user types jacobs, it will not find that object. How can I get make the filer find the object regardless of case?
This is how I currently use filter.
var user = _.filter(arr, function(item) {
return item.lastname.indexOf(typedLastName) > -1;
});
Thanks!
var user = _.filter(arr, function(item) {
return item.lastname.toLowerCase().indexOf(typedLastName.toLowerCase()) > -1;
});
Convert both of them to lowercase or uppercase , and then perform comparison

remove object from array with just the object's reference

Suppose I have an array of objects called MyArray and that a certain function returns a reference for a particular element within that array; something like this:
MyArray = [Object1, Object2, ..., Objectn];
function DoWork() {
var TheObject = GetTheObject(SomeParamter);
}
At this point, TheObject points to a certain element in the array. Suppose I want to remove this element from MyArray, is this possible without having to reloop through the array to get the index of the element?
I'm looking for something like splice that would work with the reference to the element rather than the index of the element.
Simply use Array.prototype.indexOf:
let index = MyArray.indexOf(TheObject);
if(index !== -1) {
MyArray.splice(index, 1);
}
Keep in mind that if targeting IE < 9 you will need to introduce a polyfill for indexOf; you can find one in the MDN page.

Categories

Resources