I have an object array that looks just about like this
var o = [
{
module : "mod1",
customUrl : [
{ "state" : "name1",
"options" : ["option1", "option2", "option3"]
},
{ "state" : "name2",
"options" : ["option1", "option2", "option3"]
}
]
},
{
module : "mod2",
customUrl : [
{ "state" : "name1",
"options" : ["option1", "option2", "option3"]
},
{ "state" : "name2",
"options" : ["option1", "option2", "option3"]
}
]
}
]
and in a function I a passed a string. I want to be able to check that string against the "module" keys and see if it matches any of them so like
checkName = function(name) {
//check if "name" matches any "module" in o
}
Is this possible (I am using underscore but normal javascript is fine too).Thanks!
You can use function some, like so
var checkName = function(name) {
return _.some(o, function (el) {
return el.module === name;
});
};
or some from Array
var checkName = function(name) {
return o.some(function (el) {
return el.module === name;
});
};
Example
Pure Javascript solution. This function returns false if the module name is not found or the position in the array when the name is found. This function does not count in duplicates, it only will give the position from the last match.
JSfiddle demo
var checkName = function(name) {
var flag=false;
for(var i=0; i<o.length;i++){
if(name === o[i].module){
flag=i;
}
}return flag;
};
console.log(checkName("mod2"));
Quite another way to do so wiit pure, native JavaScript: convert the object to string and check for exact module-part.
var checkName = function(haystack, needle) {
return JSON.stringify(haystack).contains('"module":"' + needle + '"')
}
checkName(o, 'mod1'); // returns true
checkName(o, 'mod4'); // returns false
Related
i have an array of objects, in which each object could have an array of objects inside.
var mylist = [
{
"email" : null,
"school" : "schoolA",
"courses": [
{
"name" : 'ABC',
"type" : "chemistry"
},
{
"name" : 'XYZ',
"type": "math"
}
]
},
{
"email" : null,
"school": "schoolB"
}
];
i want to return course name if one of the course type is chemistry.
The course types are unique and even if they are some duplicates, we return the first one.
var result = mylist.some(function (el) {
el.courses && el.courses.some(function(u) {
if (u.type === 'chemistry') {
return u.name;
};
})
});
console.log('outcome:', result);
my code is not working at this stage.
The some callback should return a truthy or falsy value, which tells some whether to keep going (true = stop), and some returns a boolean, not a callback return value.
Probably simplest in this case just to assign directly to result:
var result;
mylist.some(function(el) {
return (el.courses || []).some(function(course) {
if (course.type === "chemistry") {
result = course.name;
return true;
}
return false;
});
});
Live Example:
var mylist = [
{
"email" : null,
"school" : "schoolA",
"courses": [
{
"name" : 'ABC',
"type" : "chemistry"
},
{
"name" : 'XYZ',
"type": "math"
}
]
},
{
"email" : null,
"school": "schoolB"
}
];
var result;
mylist.some(function(el) {
return (el.courses || []).some(function(course) {
if (course.type === "chemistry") {
result = course.name;
return true;
}
return false;
});
});
console.log(result);
I stuck to ES5 syntax since you didn't use any ES2015+ in your question, but in ES2015+, simplest probably to use nested for-of loops:
let result;
outer: for (const el of mylist) {
for (const course of el.courses || []) {
if (course.type === "chemistry") {
result = course.name;
break outer;
}
}
}
Live Example:
const mylist = [
{
"email" : null,
"school" : "schoolA",
"courses": [
{
"name" : 'ABC',
"type" : "chemistry"
},
{
"name" : 'XYZ',
"type": "math"
}
]
},
{
"email" : null,
"school": "schoolB"
}
];
let result;
outer: for (const el of mylist) {
for (const course of el.courses || []) {
if (course.type === "chemistry") {
result = course.name;
break outer;
}
}
}
console.log(result);
You could use reduce() method to iterate through each object in array and then find() method to find if some course matches type.
var mylist = [{"email":null,"school":"schoolA","courses":[{"name":"ABC","type":"chemistry"},{"name":"XYZ","type":"math"}]},{"email":null,"school":"schoolB"}]
const course = mylist.reduce((r, {courses}) => {
if (courses && !r) {
const course = courses.find(({type}) => type == 'chemistry');
if (course) r = course.name;
}
return r;
}, null)
console.log(course)
I have object and this object include objects too. It looks like:
$scope.data = {
tree : {
name : 'oak',
old : 54
},
dog : {
name : 'Lucky',
old : 3
},
system1 : {
name : '',
old : ''
},
baby : {
name : 'Jack',
old : 1
},
cat : {
name : 'Fluffy',
old : 2
},
system2 : {
name : '-',
old : '-'
}
}
As you can see this objects has obj name like - tree, dog, system etc. And I want to take only objects with name system, but this name can changes like system1, system123, system8. So I try to use this reg exp for ignore numbers
replace(/\d+/g, '')
But I can't reach this object name. I try this:
angular.forEach($scope.data, function(item){conole.log(item)}) // but it shows content in obj not obj name..
How can I reach this obj name and distinguish this 2 system objects?
var data = {
tree : {
name : 'oak',
old : 54
},
dog : {
name : 'Lucky',
old : 3
},
system1 : {
name : '',
old : ''
},
baby : {
name : 'Jack',
old : 1
},
cat : {
name : 'Fluffy',
old : 2
},
system2 : {
name : '-',
old : '-'
}
}
data = Object.keys(data) // get keys
.filter(key => key.startsWith('system')) // filter keys starting with system
.map(key => data[key]) // map to the values, returning a new array
console.log(data) // and you have you array with systems
Pass another param to the function like key to the forEach callBack Function. It is the key of the each object inside the object in your use-case.
Check the below example
var items = {
car: {
a: 123
},
dog: {
b: 234
},
system: {
c: 456
}
};
angular.forEach(items, function(item, key) {
console.log(key);
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
You can use Object.keys(myObject), that return an array of all the keys of the passed object, for istance:
var myObject= {
cat : {
name : 'Fluffy',
old : 2
},
system2 : {
name : '-',
old : '-'
}
}
var keys = Object.keys(myObject); // Keys will be ['cat', 'system2']
Cheers
You have to pass another parameter to angular foreach function to get the key name of the object like this:-
angular.forEach($scope.data, function(item, key){ // Here key is the keyname of the object
console.log(item, key);
});
$scope.locations = [
{ name : "One"},
{ name : "Two"},
{ name : "Three"},
{ name : "India"},
{ name : "Japan"},
{ name : "China"}
];
$scope.tempLocations = [
{ name : "One"},
{ name : "Two"},
{ name : "global"},
];
I have two arrays. If location doesn't contain some of the names in tempLocations I want to remove them from tempLocation. In this case i want to remove location Global
I tried the following, but does not work.
for(var i=0;i<$scope.tempLocations.length;i++){
var index = $scope.tempLocations.indexOf($scope.locations[i]);
if(index == -1){
console.log($scope.tempLocations[i]);
$scope.tempLocations.splice(i,1);
}
}
I guess you're looking for this
$scope = {}
$scope.locations = [
{ name : "One"},
{ name : "Two"},
{ name : "Three"},
{ name : "India"},
{ name : "Japan"},
{ name : "China"}
];
$scope.tempLocations = [
{ name : "One"},
{ name : "Two"},
{ name : "global"},
];
$scope.tempLocations = $scope.tempLocations.filter(function(x) {
return $scope.locations.some(function(y) {
return x.name == y.name
})
})
document.getElementById("output").innerHTML = JSON.stringify($scope.tempLocations, 0,' ');
console.log($scope);
<pre id="output"></pre>
If you have many (100+) locations, consider converting them to an "associative array" first, like:
validLocations = { "One": 1, "Two": 1 ... etc
You need to loop through manually as the comment from Paul S. suggests:
var locations = [
{ name : "One"},
{ name : "Two"},
{ name : "Three"},
{ name : "India"},
{ name : "Japan"},
{ name : "China"} ];
var tempLocations = [
{ name : "One"},
{ name : "Two"},
{ name : "global"},
];
var newTempLocations = tempLocations.filter(function(temp){
return locations.some(function(location){ // stop and return true at first match
return location.name === temp.name;
});
})
// print output
document.getElementById("output").innerHTML = JSON.stringify(newTempLocations, null, " ");
<pre id="output"></pre>
If $scope.locations isn't going to change often, you could do the following:
Build a lookup table for locations
var location_lookup = {};
for ( var i = 0; i < $scope.locations.length; i++ ) {
location_lookup[$scope.locations[i].name] = true;
}
Filter based on the existence of a key
$scope.filteredLocations = $scope.tempLocations.filter(function(temp) {
return location_lookup.hasOwnProperty(temp.name);
});
This will prove to be much faster if you're filtering more often than you need to recompute the lookup. So if $scope.locations is static, this would be a good route.
I would advise against using temp.name in location_lookup as another poster said to since that will also check ALL of the prototyped properties of the location_lookup object. For instance, if another script in your app did Object.prototype.global = function(){} then the filter would return "global" as being part of $scope.locations, which is not the behavior you want. hasOwnProperty will only check the object itself and not any prototypical inheritance while also being a more efficient method.
Fiddle Demonstration: http://jsfiddle.net/cu33ojfy/ (also included an implementation that uses Array.prototype to add a .filter_locations() method, but adding to Array.prototype is generally a bad idea)
I have this kind of array:
var foo = [ { "a" : "1" }, { "b" : "2" }, { "a" : "1" } ];
I'd like to filter it to have:
var bar = [ { "a" : "1" }, { "b" : "2" }];
I tried using _.uniq, but I guess because { "a" : "1" } is not equal to itself, it doesn't work. Is there any way to provide underscore uniq with an overriden equals function?
.uniq/.unique accepts a callback
var list = [{a:1,b:5},{a:1,c:5},{a:2},{a:3},{a:4},{a:3},{a:2}];
var uniqueList = _.uniq(list, function(item, key, a) {
return item.a;
});
// uniqueList = [Object {a=1, b=5}, Object {a=2}, Object {a=3}, Object {a=4}]
Notes:
Callback return value used for comparison
First comparison object with unique return value used as unique
underscorejs.org demonstrates no callback usage
lodash.com shows usage
Another example :
using the callback to extract car makes, colors from a list
If you're looking to remove duplicates based on an id you could do something like this:
var res = [
{id: 1, content: 'heeey'},
{id: 2, content: 'woah'},
{id: 1, content:'foo'},
{id: 1, content: 'heeey'},
];
var uniques = _.map(_.groupBy(res,function(doc){
return doc.id;
}),function(grouped){
return grouped[0];
});
//uniques
//[{id: 1, content: 'heeey'},{id: 2, content: 'woah'}]
Implementation of Shiplu's answer.
var foo = [ { "a" : "1" }, { "b" : "2" }, { "a" : "1" } ];
var x = _.uniq( _.collect( foo, function( x ){
return JSON.stringify( x );
}));
console.log( x ); // returns [ { "a" : "1" }, { "b" : "2" } ]
When I have an attribute id, this is my preffered way in underscore:
var x = [{i:2}, {i:2, x:42}, {i:4}, {i:3}];
_.chain(x).indexBy("i").values().value();
// > [{i:2, x:42}, {i:4}, {i:3}]
Using underscore unique lib following is working for me, I m making list unique on the based of _id then returning String value of _id:
var uniqueEntities = _.uniq(entities, function (item, key, a) {
return item._id.toString();
});
Here is a simple solution, which uses a deep object comparison to check for duplicates (without resorting to converting to JSON, which is inefficient and hacky)
var newArr = _.filter(oldArr, function (element, index) {
// tests if the element has a duplicate in the rest of the array
for(index += 1; index < oldArr.length; index += 1) {
if (_.isEqual(element, oldArr[index])) {
return false;
}
}
return true;
});
It filters out all elements if they have a duplicate later in the array - such that the last duplicate element is kept.
The testing for a duplicate uses _.isEqual which performs an optimised deep comparison between the two objects see the underscore isEqual documentation for more info.
edit: updated to use _.filter which is a cleaner approach
The lodash 4.6.1 docs have this as an example for object key equality:
_.uniqWith(objects, _.isEqual);
https://lodash.com/docs#uniqWith
Try iterator function
For example you can return first element
x = [['a',1],['b',2],['a',1]]
_.uniq(x,false,function(i){
return i[0] //'a','b'
})
=> [['a',1],['b',2]]
here's my solution (coffeescript) :
_.mixin
deepUniq: (coll) ->
result = []
remove_first_el_duplicates = (coll2) ->
rest = _.rest(coll2)
first = _.first(coll2)
result.push first
equalsFirst = (el) -> _.isEqual(el,first)
newColl = _.reject rest, equalsFirst
unless _.isEmpty newColl
remove_first_el_duplicates newColl
remove_first_el_duplicates(coll)
result
example:
_.deepUniq([ {a:1,b:12}, [ 2, 1, 2, 1 ], [ 1, 2, 1, 2 ],[ 2, 1, 2, 1 ], {a:1,b:12} ])
//=> [ { a: 1, b: 12 }, [ 2, 1, 2, 1 ], [ 1, 2, 1, 2 ] ]
with underscore i had to use String() in the iteratee function
function isUniq(item) {
return String(item.user);
}
var myUniqArray = _.uniq(myArray, isUniq);
I wanted to solve this simple solution in a straightforward way of writing, with a little bit of a pain of computational expenses... but isn't it a trivial solution with a minimum variable definition, is it?
function uniq(ArrayObjects){
var out = []
ArrayObjects.map(obj => {
if(_.every(out, outobj => !_.isEqual(obj, outobj))) out.push(obj)
})
return out
}
var foo = [ { "a" : "1" }, { "b" : "2" }, { "a" : "1" } ];
var bar = _.map(_.groupBy(foo, function (f) {
return JSON.stringify(f);
}), function (gr) {
return gr[0];
}
);
Lets break this down. First lets group the array items by their stringified value
var grouped = _.groupBy(foo, function (f) {
return JSON.stringify(f);
});
grouped looks like:
{
'{ "a" : "1" }' = [ { "a" : "1" } { "a" : "1" } ],
'{ "b" : "2" }' = [ { "b" : "2" } ]
}
Then lets grab the first element from each group
var bar = _.map(grouped, function(gr)
return gr[0];
});
bar looks like:
[ { "a" : "1" }, { "b" : "2" } ]
Put it all together:
var foo = [ { "a" : "1" }, { "b" : "2" }, { "a" : "1" } ];
var bar = _.map(_.groupBy(foo, function (f) {
return JSON.stringify(f);
}), function (gr) {
return gr[0];
}
);
You can do it in a shorthand as:
_.uniq(foo, 'a')
When I have a JavaScript object like this:
var member = {
"mother": {
"name" : "Mary",
"age" : "48"
},
"father": {
"name" : "Bill",
"age" : "50"
},
"brother": {
"name" : "Alex",
"age" : "28"
}
}
How to count objects in this object?!
I mean how to get a counting result 3, because there're only 3 objects inside: mother, father, brother?!
If it's not an array, so how to convert it into JSON array?
That's not an array, is an object literal, you should iterate over the own properties of the object and count them, e.g.:
function objectLength(obj) {
var result = 0;
for(var prop in obj) {
if (obj.hasOwnProperty(prop)) {
// or Object.prototype.hasOwnProperty.call(obj, prop)
result++;
}
}
return result;
}
objectLength(member); // for your example, 3
The hasOwnProperty method should be used to avoid iterating over inherited properties, e.g.
var obj = {};
typeof obj.toString; // "function"
obj.hasOwnProperty('toString'); // false, since it's inherited
You can try this code, it works perfectly in a browser:
Object.keys(member).length;
If you are using jquery on your page, this will work:
$(member).toArray().length;
You can use the Object.keys() method that returns an array of a given object's own enumerable properties:
Object.keys(member).length;
That is not an array, it is an object literal.
You can iterate the objects properties and count how many it owns:
var count = 0;
for (var k in obj) {
// if the object has this property and it isn't a property
// further up the prototype chain
if (obj.hasOwnProperty(k)) count++;
}
var member = {
"mother": {
"name" : "Mary",
"age" : "48"
},
"father": {
"name" : "Bill",
"age" : "50"
},
"brother": {
"name" : "Alex",
"age" : "28"
}
}
console.log('member key size:' + Object.keys(member).length);
ref a good guy : https://stackoverflow.com/questions/5223/length-of-a-javascript-object
Here's how I'd do it
function getObjectLength( obj )
{
var length = 0;
for ( var p in obj )
{
if ( obj.hasOwnProperty( p ) )
{
length++;
}
}
return length;
}
In my practice I work like this:
/*
* $.count(array) - Returns the number of elements in an array (immproved equivalent to .length property).
*/
$.count = function (array){
if(array.length)
return array.length;
else
{
var length = 0;
for ( var p in array ){if(array.hasOwnProperty(p)) length++;};
return length;
}
}