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.
Related
I am having one array with some values like below,
let a = ["Mango","1243greatApple","goodOrange","Watermelon","ThisGoodalsoberemoved","GreatOrange","Pappaya","BestApple"];
Now, I want to eliminate the values which contains string like Great and Good in the values.
Expecting output like below,
["Mango","Watermelon","Pappaya","BestApple"]
Tried using lodash, but it works only when it matches exact string. But i need it like regex match. Please help me out with this.
In vanilla JS, you can try with Array.prototype.filter()
The filter() method creates a new array with all elements that pass the test implemented by the provided function.
And String.prototype.includes()
The includes() method determines whether one string may be found within another string, returning true or false as appropriate.
let a = ["Mango","1243GreatApple","GoodOrange","Watermelon","ThisGoodalsoberemoved","GreatOrange","Pappaya","BestApple"];
var r = a.filter(f => !(f.includes('Great') || f.includes('Good')));
console.log(r);
Why is lodash returning -1 here? It's clearly in there?
Ignores = ['load', 'test', 'ok'];
alert(_.findIndex(Ignores, 'ok') );
That's because findIndex() takes as parameters an array and a predicate, a function that returns a boolean value based on some condition.
Assuming you are searching for needle in haystack, you can achieve what you want with normal JavaScript:
alert(haystack.indexOf(needle));
You can use _.indexOf (from #Juhana):
alert(_.indexOf(haystack, needle))
You can do it with _.findIndex too:
alert(_.findIndex(haystack, function(x) { return x === needle; }));
or:
alert(_.findIndex(haystack, _(needle).isEqual));
The loadash _.findIndex is quite work in different order of the JSON structure.If you would like to get the index of the array object based upon the nested structure.The lodash has provided the same special way to do it.
Let assume if your JSON structure is like below mentioned pattern.
lstMainArray:
[{searhName:'Abc1',searchName:'Abc2'}]
and you would like to search from nested JSNO such as :
searchObject :
{
searchField:{
searchName:'Abc1'
}
}
you can make the below syntax to use it.
_.findIndex(lstMainArray,['searchField.searchName','Abc1']);
I have an observable array of objects and I want to pluck out the values using underscore.js
For example:
ko.observableArray([{
id: ko.observable(1),
name: ko.observable("name1")
},
{
id: ko.observable(2),
name: ko.observable("name2")
},
...])
And I just want to pluck the values inside of the object rather than the whole observable.
Can I do this with just one command?
I tried:
_.pluck(myArray(), "id()") and _.pluck(myArray(), "id"())
But these return an array of undefineds and "id is not a function" respectively.
Thanks!
Short answer
Use _.invoke instead of _.pluck
See this sample fiddle.
Long answer
_.pluck(list, propertyName) works as documented:
A convenient version of what is perhaps the most common use-case for map: extracting a list of property values.
Or, as better exlained on lodash docs: _.pluck(collection, path)
Gets the property value of path from all elements in collection.
So, if you do this:
_.pluck(myArray(), "id")
what you get is an array with all the id's. And all of these id's are observables, as in the objects of the original array
But you can use _.invoke(list, methodName, *arguments), which, as documented:
Calls the method named by methodName on each value in the list. Any extra arguments passed to invoke will be forwarded on to the method invocation.
or, on lodash version _.invoke(collection, path, [args])
Invokes the method at path on each element in collection, returning an array of the results of each invoked method. Any additional arguments are provided to each invoked method. If methodName is a function it is invoked for, and this bound to, each element in collection.
In this way, you execute each observable, and get its value as expected:
_.invoke(myArray(), "id")
Mind the viewmodels full of observables!
The first comment to this question has made me include this notice:
The best solution is using ko.toJS to convert all the observables in a view model into a regular JavaScript object, with regular properties. Once you do it, underscore, or any other library, will work as expected.
The _.invoke solution only works for a single level of observables, as this case. If there were several level of nested observables, it will completely fail, because it invokes a function at the end of the path, not at each step of the path, for example, _.invoke wouldn't work for this case:
var advices = [{
person: ko.observable({
name = ko.observable('John')
}),
advice: ko.observable('Beware of the observables!')
}];
In this case, you could only use _.invoke on the first level, like this:
var sentences = _.invoke(advices,'advice');
But this wouldn't work:
var names = _.invoke(advices,'person.name');
In this call, only name would be invoked, but person not, so this would fail, because person is an observable, thus it doesn't have a name property.
NOTE: lodash is another library similar, and mostly compatible with underscore, but better in some aspects
I was able to solve this by using the "map" function:
_.map(myArray(), function(item) {return item.id()});
But I was hoping to use pluck since it's the exact use-case for this type of scenario.
Because name is a function, how about pluck your original array into an array of functions, then using ko.toJS to convert it into string array?
var myArray = ko.observableArray([{
id: ko.observable(1),
name: ko.observable("name1")
},
{
id: ko.observable(2),
name: ko.observable("name2")
}]);
var names = _.pluck(myArray(), 'name');
console.log(ko.toJS(names)); // Output: ["name1", "name2"]
Unwrap it first
_.pluck(ko.toJS(myArray), 'id')
_(ko.toJS(myArray)).pluck('id)
I'm reading on the map/reduce documentation and this particular string example doesn't make sense to me.
var toCode = function(char) {
return char.charCodeAt(0);
}
First, the thing that works. Why does it work? string is not an array.
var text = "Hello World";
var map = Array.prototype.map;
console.log(map.call(text, toCode));
Now, the thing that doesn't work. Isn't this exactly the same as above?
console.log(text.map(toCode));
I use www.codeacademy.com console to test and this is the error message:
TypeError: undefined is not a function (evaluating '"hello world".map(toCode)')
Thank you.
Your second code won't work because strings don't have a map method, but you can borrow it from Array, because array methods are meant to work on array-like objects, that is an object with numeric keys, such as strings:
The map function is intentionally generic; it does not require that
its this value be an Array object. Therefore it can be transferred to
other kinds of objects for use as a method. Whether the map function
can be applied successfully to a host object is
implementation-dependent.
http://www.ecma-international.org/ecma-262/5.1/#sec-15.4.4.19
I was trying to define an array (including other arrays as values) in a single javascript statement, that I can loop through to validate a form on submission.
The function I wrote to (try to) create inline arrays follows:
function arr(){
var inc;
var tempa = new Array(Math.round(arguments.length/2));
for(inc=0; inc<arguments.length; inc=inc+2) {
tempa[arguments[inc]]=arguments[inc+1];
}
return tempa;
}
This is called three times here to assign an array:
window.validArr = arr(
'f-county',arr('maxlen',10, 'minlen',1),
'f-postcode',arr('maxlen',8, 'minlen',6)
);
However in the javascript debugger the variable is empty, and the arr() function is not returning anything. Does anyone know why my expectations on what this code should do are incorrect?
(I have worked out how to create the array without this function, but I'm curious why this code doesn't work (I thought I understood javascript better than this).)
Well from what your code does, you're not really making arrays. In JavaScript, the thing that makes arrays special is the management of the numerically indexed properties. Otherwise they're just objects, so they can have other properties too, but if you're not using arrays as arrays you might as well just use objects:
function arr(){
var inc;
var tempa = {};
for(inc=0; inc<arguments.length; inc=inc+2) {
tempa[arguments[inc]]=arguments[inc+1];
}
return tempa;
}
What you're seeing from the debugger is the result of it attempting to show you your array as a real array should be shown: that is, its numerically indexed properties. If you call your "arr()" function as is and then look at (from your example) the "f-county" property of the result, you'll see something there.
Also, if you do find yourself wanting a real array, there's absolutely no point in initializing them to a particular size. Just create a new array with []:
var tempa = [];
Your code works. Just inspect your variable, and you will see that the array has the custom keys on it. If not expanded, your debugger shows you just the (numerical) indixed values in short syntax - none for you.
But, you may need to understand the difference between Arrays and Objects. An Object is just key-value-pairs (you could call it a "map"), and its prototype. An Array is a special type of object. It has special prototype methods, a length functionality and a different approach: to store index-value-pairs (even though indexes are still keys). So, you shouldn't use an Array as an associative array.
Therefore, their literal syntax differs:
var array = ["indexed with key 0", "indexed with key 1", ...];
var object = {"custom":"keyed as 'custom'", "another":"string", ...};
// but you still can add keys to array objects:
array.custom = "keyed as 'custom'";