Lowercase of object value in array with underscore js - javascript

Let's say I have this JSON data in a data variable
[{"id":"1","module_id":"1","title":"Test",
"start_date":"2012-11-12" "end_date":"2012-11-18"},
{"id":"8","module_id":"1","title":"This is OK",
"start_date":"2013-01-14","end_date":"2013-01-31"}]
How do I use underscore.js to get following result?
[{"id":"1","module_id":"1","title":"test",
"start_date":"2012-11-12","end_date":"2012-11-18"},
{"id":"8","module_id":"1","title":"this is ok",
"start_date":"2013-01-14","end_date":"2013-01-31"}]
Can I do this with invoke ?

You can do this easily with Lo Dash's _.mapValues function:
_.mapValues(objs, function(s){
return _.isString(s) ? s.toLowerCase() : s;
});

If you're already dealing with an object (or parsed JSON), you can loop and create a new one:
var objs = [{"id":"1","module_id":"1","title":"Test", "start_date":"2012-11-12", "end_date":"2012-11-18"},{"id":"8","module_id":"1","title":"This is OK", "start_date":"2013-01-14","end_date":"2013-01-31"}];
var out = [];
for(var i=0; i<objs.length; i++) {
var outObj = {}
for(var prop in objs[i]) {
var val = objs[i][prop];
if(prop === 'title') {
val = val.toLowerCase();
}
outObj[prop] = val;
}
out.push(outObj);
}
console.log(out);
http://jsfiddle.net/uY36J/

If you have array of objects:
for(var i = 0; i < array.length; i++) {
for (var prop in array[i])
// condition here
array[i][prop] = array[i][prop].toLowerCase();
}
console.log(array)
Same with underscore (I don't think it's much shorter - you still need two loops here. More readable - maybe, but not shorter)
_.each(array, function(obj) {
_.each(obj, function(value, key) {
// condition here
obj[key] = value.toLowerCase();
});
});

You can separate the object in two arrays, one with the keys and the other with the values, then use _.map to lowercase the strings.
var objs = [{"id":"1","module_id":"1","title":"Test", "start_date":"2012-11-12", "end_date":"2012-11-18"},{"id":"8","module_id":"1","title":"This is OK", "start_date":"2013-01-14","end_date":"2013-01-31"}];
_.map(objs,function(element) {
return _.object(_.keys(element), _.values(element).map(function(value) {
return _.isString(value)? value.toLowerCase():value;
}));
});
you see, I'm checking if it's a string we're dealing with, to avoid calling toLowerCase on other types.
Lowercasing both keys and values is trivial as well
_.map(objs,function(element) {
return _.object(
_.keys(element).map(function(key) {
return _.isString(key)? key.toLowerCase():key;
}),
_.values(element).map(function(value) {
return _.isString(value)? value.toLowerCase():value;
})
);
});
Caveat: this will not operate on nested objects. ¯\_(ツ)_/¯

Related

Find key contain dot and replace with #

I have nested object which can have any number of key at any depth.
I want to replace "." in all keys(if contain) with "#" How we can do this in efficient way.
Example Node js object
obj:{
"BotBuilder.Data.SessionState": {
"lastAccess": 1492886892545,
"version": 14,
"callstack": [
{
"id": "*:/",
"state": {
"BotBuilder.Data.WaterfallStep": 0,
"BotBuilder.Data.Intent": "welcomeDialog"
}
}
]
}
Currently i am using hard coded solution , but any keys can be possible in object at any level which contain "." I want generalize way to solve this problem
My code :
replaceDot:function(doc){
var finalobj={}
var finaldata={}
var finalcallstack=new Array();
console.log("doc==>",doc)
var callstack=doc["data"]["BotBuilder.Data.SessionState"]["callstack"]
for(var i = 0; i < callstack.length; i++) {
var tempcallstack={}
if("BotBuilder.Data.WaterfallStep" in callstack[i]["state"]){
tempcallstack["id"]=callstack[i]["id"]
var tempstate={}
tempstate["state"]=callstack[i]["state"]
tempstate["state"]["BotBuilder#Data#WaterfallStep"]=tempstate["state"]["BotBuilder.Data.WaterfallStep"]
tempstate["state"]["BotBuilder#Data#Intent"]=tempstate["state"]["BotBuilder.Data.Intent"]
delete tempstate["state"]["BotBuilder.Data.WaterfallStep"]
delete tempstate["state"]["BotBuilder.Data.Intent"]
tempcallstack["state"]=tempstate["state"];
finalcallstack.push(tempcallstack);
}
else{
finalcallstack.push(callstack[i]);
}
}
var obj={}
finalobj["lastAccess"]=doc["data"]["BotBuilder.Data.SessionState"]["lastAccess"]
finalobj["version"]=doc["data"]["BotBuilder.Data.SessionState"]["version"]
finalobj["callstack"]=finalcallstack;
obj["BotBuilder#Data#SessionState"]=finalobj
var secondrootobj={"BotBuilder#Data#SessionState":finalobj}
return secondrootobj;
}
Here's a function that takes an object or array, and target and replacement values for the keys of that object. It will then return a new object where instances of target are replaced with replacement (using String.prototype.replace) in the resulting object's keys.
var substituteKeyDeep = function(obj, target, replacement) {
// Get the type of the object. Array for arrays, Object for objects, null for anything else.
try {
var type = obj.constructor === Array ? Array
: (obj.constructor === Object ? Object : null);
} catch (err) {
// A try/catch is actually necessary here. This is because trying to access the `constructor` property
// of some values throws an error. For example `null.constructor` throws a TypeError.
var type = null;
}
if (type === Array) {
// Simply do a recursive call on all values in array
var ret = [];
for (var i = 0, len = obj.length; i < len; i++) {
ret[i] = substituteKeyDeep(obj[i], target, replacement);
}
} else if (type === Object) {
// Do a recursive call on all values in object, AND substitute key values using `String.prototype.replace`
var ret = {};
for (var k in obj) {
ret[k.replace(target, replacement)] = substituteKeyDeep(obj[k], target, replacement);
}
} else {
// For values that aren't objects or arrays, simply return the value
var ret = obj;
}
return ret;
};
var data = {
"BotBuilder.Data.SessionState": {
"lastAccess": 1492886892545,
"version": 14,
"callstack": [
{
"id": "*:/",
"state": {
"BotBuilder.Data.WaterfallStep": 0,
"BotBuilder.Data.Intent": "welcomeDialog"
}
}
]
}
};
var dataWithRenamedKeys = substituteKeyDeep(data, /\./g, '#');
console.log(dataWithRenamedKeys);
Note that in the example, the replacement value (/\./g) is a regex expression, not a string. This is because a regex expression with the global modifier (g) is required to replace ALL instances of the occurrence, not just the first, in the object's keys.
EDIT: Quick disclaimer! This solution will exceed the stack if substituteKeyDeep is called with an object that has circular references.

Update: Unexpected results when using updated 'contains' method. Changes value of foreach 'key'

I start with 2 string arrays:
var ny_students = [......];
var la_student = [.....];
I've got this bit of code that adds to the array:
for (i=0;i<array.length;i++) {
if (ny_students.contains(array[i]["Result"])){
array[i].Class = "Advanced";
}
else{
if (la_students.contains(array[i]["Result"])){
array[i].Class = "General";
}
else{
if (i==0) {
array.splice(i,1);
}
else {
array.splice(i-1,1);
}
i--;
}
}
}
I am getting unexpected results; the 'key' value somehow becomes 'contains'. Here is the 'contains' method definition:
Array.prototype.contains = function ( needle ) {
for (i in this) {
if (this[i] == needle) return true;
}
return false;
}
Adding to the Array.prototype the way you have will make the contains function enumerable and thus appear in the for...in loop
This is why you never use for...in on an array
Alternatively, define contains in such a way that is is not enumerable
Object.defineProperty(Array.prototype, 'contains', {
configurable: true,
value: function ( needle ) {
for (var i = 0; i < this.length; i++) {
if (this[i] == needle) return true;
}
return false;
}
});
The for...in syntax in JS iterates over "iterable" properties of objects, and there is no promise that they'll be returned in order. Sadly enough, the creators of JS didn't think things through and made the "length" property iterable. So we're stuck with using the lame syntax:
for(var i=0; i<arr.length; ++i) { ... }
You don't need your own contains method because arr.indexOf(n) will return -1 if the value n isn't found. So just do if(arr.indexOf(n) !== -1) to check if a value is in the array.
Finally, the array has a concat method which can combine two arrays (not sure if that will be useful to you in that code, but it's worth pointing out). So if you need to check if a value is in one of two arrays, you could just do :
if(arr1.concat(arr2).indexOf(n) != -1) { ... }
Note that the elements of arr2 don't get added to arr1 when you do that - it actually returns a new array which contains the elements of both arrays.

Remove false values in object

The problem that I'm facing is -removing the values in the onject that has the property false
Here is the object
var myObj={105:true,183:false,108:true,106:false}
I'm able to get the values in an array by using the following logic:
Object.keys(myObj) gives ["105","183","108","106"]
But I need a way to remove the values that have the property false and generate as ["105",108"].Can you help me out ?
You have the keys of the object in an array. Run filter over it.
var myObj={105:true,183:false,108:true,106:false};
var result = Object.keys(myObj).filter(function(x) {
return myObj[x] !== false;
});
// result = ["105", "108"]
I've just created a solution to your problem on JSBin: Working Demo
Please find below the code:
var myObj={105:true,183:false,108:true,106:false};
var myArray = [];
function RemoveFalseAndTransformToArray () {
for (var key in myObj) {
if(myObj[key] === false) {
delete myObj[key];
} else {
myArray.push(key);
}
}
}
RemoveFalseAndTransformToArray();
console.log("myObj: ", myObj);
console.log("myArray: ", myArray);
// result = ["105", "108"]
Please, let me know if you have any question.
To remove those properties you can use this algorithm:
for (k in myObj)
{
if (myObj.hasOwnProperty(k) && myObj[k] === false)
{
delete myObj[k];
}
}
If you are just interested in the keys of non-false values, you can use:
var keys = Object.keys(myObj).filter(function (k) {
return myObj[k] !== false;
});
The hasOwnProperty() check is necessary because objects may contain non-user properties (such as prototype) which you really don't want to mess with.
You need to iterate over the object using for...in loop
var myObj={105:true,183:false,108:true,106:false}
for(var key in myObj){
if(myObj.hasOwnProperty(key) && myObj[key] == false){
delete myObj[key];
}
}
console.log(JSON.stringify(myObj)) //{"105":true,"108":true}
console.log(Object.keys(myObj)) //["105", "108"]
ES6 has a one line way to do this, this mutates the original array!
Object.keys(myObj).map(key => !myObj[key] && delete myObj[key])
to avoid this use the spread operator
const filteredObj = [...myObj]
Object.keys(filteredObj).map(key => !filteredObj[key] && delete filteredObj[key])

How do I write a recursive function in Javascript to add up all of the string values of a deeply nested object?

Say I have this object:
{
"prop1":"Hello",
"prop2":{
"prop1":{
"prop1":"Tablecloth",
"prop2":"Indians"
},
"prop2":"JuicyJuice"
},
"prop3":"Sponge",
"prop4":{"Bob":"Squarepants"}
}
I would like a recursive function that will return HelloTableclothIndiansJuicyJuiceSpongeSquarepants.
Whatever object I put it, I want it to cycle though until it gets all of the strings and adds them all up.
Thank you!
Here's a very simple implementation that should work for simple objects like this:
var walkProps = function(obj) {
var s = "";
for(var x in obj)
{
if(typeof obj[x] === "string")
s += obj[x];
else
s += walkProps(obj[x]);
}
return s;
}
Demonstration
Note, though, that that depends on the order in which for-in visits the properties on the object, which is not specified and can vary by engine and by how the object is constructed (for instance, the order in which the properties were added).
Update: With some slight modification, this can be used to return the values based on the alphabetical order of the keys. This method is not sensitive to implementation-dependent ordering of properties:
var walkProps = function(obj) {
var s = "", i = 0, keys = Object.keys(obj).sort(), i;
for(; i < keys.length; i++)
{
if(typeof obj[keys[i]] === "string")
s += obj[keys[i]];
else
s += walkProps(obj[keys[i]]);
}
return s;
}
So even if "prop3" comes before "prop2" it will still return the same output.
Demonstration
You would need to write a function that loops over an object's properties and see if they are a string, and then append the strings to an output. If the property is an object rather than a string, you would want to call the function on this object and append it's return value to your total output.
You can loop over an object's properties using for...in like:
var MyObject = {
'a': 'string1',
'b': 'string2'
};
for (var key in MyObject) {
var value = MyObject[key];
}
To check if a property is a string you would want to do:
typeof value === "string"
Which will return true/false accordingly.
As mentioned, for( var b in a ) may not preserve ordering:
// Return array of string values
function getStrings(a) {
if( typeof(a) == "string" ) return [a];
var list = [];
for( var b in a ) list = list.concat(getStrings(a[b]));
return list;
}
Applied to OP's data:
var a = {
"prop1":"Hello",
"prop2":{
"prop1":{
"prop1":"Tablecloth",
"prop2":"Indians"
},
"prop2":"JuicyJuice"
},
"prop3":"Sponge",
"prop4":{"Bob":"Squarepants"}
}
getStrings(a).join(); // "Hello,Tablecloth,Indians,JuicyJuice,Sponge,Squarepants"
// Or as asked for by OP (again, order is not guaranteed)
getStrings(a).join(''); // "HelloTableclothIndiansJuicyJuiceSpongeSquarepants"

How to determine if object is in array [duplicate]

This question already has answers here:
How do I check if an array includes a value in JavaScript?
(60 answers)
Closed 29 days ago.
I need to determine if an object already exists in an array in javascript.
eg (dummycode):
var carBrands = [];
var car1 = {name:'ford'};
var car2 = {name:'lexus'};
var car3 = {name:'maserati'};
var car4 = {name:'ford'};
carBrands.push(car1);
carBrands.push(car2);
carBrands.push(car3);
carBrands.push(car4);
now the "carBrands" array contains all instances.
I'm now looking a fast solution to check if an instance of car1, car2, car3 or car4 is already in the carBrands array.
eg:
var contains = carBrands.Contains(car1); //<--- returns bool.
car1 and car4 contain the same data but are different instances they should be tested as not equal.
Do I have add something like a hash to the objects on creation? Or is there a faster way to do this in Javascript.
I am looking for the fastest solution here, if dirty, so it has to be ;) In my app it has to deal with around 10000 instances.
no jquery
Use something like this:
function containsObject(obj, list) {
var i;
for (i = 0; i < list.length; i++) {
if (list[i] === obj) {
return true;
}
}
return false;
}
In this case, containsObject(car4, carBrands) is true. Remove the carBrands.push(car4); call and it will return false instead. If you later expand to using objects to store these other car objects instead of using arrays, you could use something like this instead:
function containsObject(obj, list) {
var x;
for (x in list) {
if (list.hasOwnProperty(x) && list[x] === obj) {
return true;
}
}
return false;
}
This approach will work for arrays too, but when used on arrays it will be a tad slower than the first option.
Why don't you use the indexOf method of javascript arrays?
Check this out: MDN indexOf Arrays
Simply do:
carBrands.indexOf(car1);
It will return you the index (position in the array) of car1. It will return -1 if car1 was not found in the array.
http://jsfiddle.net/Fraximus/r154cd9o
Edit: Note that in the question, the requirements are to check for the same object referenced in the array, and NOT a new object. Even if the new object is identical in content to the object in the array, it is still a different object.
As mentioned in the comments, objects are passed by reference in JS and the same object can exist multiple times in multiple structures.
If you want to create a new object and check if the array contains objects identical to your new one, this answer won't work (Julien's fiddle below), if you want to check for that same object's existence in the array, then this answer will work. Check out the fiddles here and in the comments.
Having been recently bitten by the FP bug reading many wonderful accounts of how neatly the functional paradigm fits with Javascript
I replicate the code for completeness sake and suggest two ways this can be done functionally.
var carBrands = [];
var car1 = {name:'ford'};
var car2 = {name:'lexus'};
var car3 = {name:'maserati'};
var car4 = {name:'ford'};
var car5 = {name:'toyota'};
carBrands.push(car1);
carBrands.push(car2);
carBrands.push(car3);
carBrands.push(car4);
// ES6 approach which uses the includes method (Chrome47+, Firefox43+)
carBrands.includes(car1) // -> true
carBrands.includes(car5) // -> false
If you need to support older browsers use the polyfill, it seems IE9+ and Edge do NOT support it. Located in polyfill section of MSDN page
Alternatively I would like to propose an updated answer to cdhowie
// ES2015 syntax
function containsObject(obj, list) {
return list.some(function(elem) {
return elem === obj
})
}
// or ES6+ syntax with cool fat arrows
function containsObject(obj, list) {
return list.some(elem => elem === obj)
}
try Array.prototype.some()
MDN Array.prototype.some
function isBiggerThan10(element, index, array) {
return element > 10;
}
[2, 5, 8, 1, 4].some(isBiggerThan10); // false
[12, 5, 8, 1, 4].some(isBiggerThan10); // true
You could use jQuery's grep method:
$.grep(carBrands, function(obj) { return obj.name == "ford"; });
But as you specify no jQuery, you could just make a derivative of the function. From the source code:
function grepArray( elems, callback, inv ) {
var ret = [];
// Go through the array, only saving the items
// that pass the validator function
for ( var i = 0, length = elems.length; i < length; i++ ) {
if ( !inv !== !callback( elems[ i ], i ) ) {
ret.push( elems[ i ] );
}
}
return ret;
}
grepArray(carBrands, function(obj) { return obj.name == "ford"; });
I used underscore javascript library to tweak this issue.
function containsObject(obj, list) {
var res = _.find(list, function(val){ return _.isEqual(obj, val)});
return (_.isObject(res))? true:false;
}
please refer to underscore.js documentation for the underscore functions used in the above example.
note: This is not a pure javascript solution. Shared for educational purposes.
You can just use the equality operator: ==. Objects are checked by reference by default, so you don't even need to use the === operator.
try this, just make sure you're using the correct variable reference in the place of car1:
var i, car, l = cars.length;
for (i = 0; i < l; i++)
{
if ((car = cars[i]) == car1)
{
break;
}
else car = null;
}
Edit to add:
An array extension was mentioned, so here's the code for it:
Array.prototype.contains = Array.prototype.contains || function(obj)
{
var i, l = this.length;
for (i = 0; i < l; i++)
{
if (this[i] == obj) return true;
}
return false;
};
Note that I'm caching the length value, as the Array's length property is actually an accessor, which is marginally slower than an internal variable.
I would use a generic iterator of property/value over the array. No jQuery required.
arr = [{prop1: 'val1', prop2: 'val2'}, {prop1: 'val3', prop2: 'val4'}];
objectPropInArray(arr, 'prop1', 'val3'); // <-- returns true
function objectPropInArray(list, prop, val) {
if (list.length > 0 ) {
for (i in list) {
if (list[i][prop] === val) {
return true;
}
}
}
return false;
}
You could try sorting the array based on a property, like so:
carBrands = carBrands.sort(function(x,y){
return (x == y) ? 0 : (x > y) ? 1 : -1;
});
Then you can use an iterative routine to check whether
carBrands[Math.floor(carBrands.length/2)]
// change carBrands.length to a var that keeps
// getting divided by 2 until result is the target
// or no valid target exists
is greater or lesser than the target, and so on, which will let you go through the array quickly to find whether the object exists or not.
try this ,
You can use the JavaScript some() method to find out if a JavaScript array contains an object.
<script>
// An array of objects
var persons = [{name: "Harry"}, {name: "Alice"}, {name: "Peter"}];
// Find if the array contains an object by comparing the property value
if(persons.some(person => person.name === "Peter")){
alert("Object found inside the array.");
} else{
alert("Object not found.");
}
</script>
EDIT 05/18/2022
The most simple way using ES6:
const arrayContainsObject = <T extends Record<string, unknown>>(array: T[], object: T) => {
return array.some(item => Object.keys(item).every(key => item[key] === object[key]))
}
Use like so:
const arr = [{
prop1: 'value1',
prop2: 'value2'
}]
const obj1 = {
prop1: 'value1',
prop2: 'value2'
}
const obj2 = {
prop2: 'value2',
prop1: 'value1'
}
const obj3 = {
prop0: 'value0',
prop1: 'value1'
}
arrayContainsObject(arr, obj1) // true
arrayContainsObject(arr, obj2) // true, even when props are arranged in different order
arrayContainsObject(arr, obj3) // false
Previous answer, don't use (because the order of props in an object needs to be identical)
const arr = [{
prop: 'value'
}]
const obj = {
prop: 'value'
}
arr.some((e) => Object.entries(e).toString() === Object.entries(obj).toString()) // true
i know this is an old post, but i wanted to provide a JQuery plugin version and my code.
// Find the first occurrence of object in list, Similar to $.grep, but stops searching
function findFirst(a,b){
var i; for (i = 0; i < a.length; ++i) { if (b(a[i], i)) return a[i]; } return undefined;
}
usage:
var product = $.findFirst(arrProducts, function(p) { return p.id == 10 });
This function is to check for a unique field.
Arg 1: the array with selected data
Arg 2: key to check
Arg 3: value that must be "validated"
function objectUnique( array, field, value )
{
var unique = true;
array.forEach(function ( entry )
{
if ( entry[field] == value )
{
unique = false;
}
});
return unique;
}
you can use Array.find().
in your case is going to look like this
carBrands.find(function(car){
let result = car.name === 'ford'
if (result == null){
return false;
} else {
return true
}
});
if car is not null it will return the javaScript Object which contains the string 'ford'
The issue with many of the answers here is that they will NOT find an object in an array that is equal to another object. They will only search for an EXISTING object that has a pointer to it in an array.
Quick fix using lodash to see if ANY equal object is in an array:
import _ from 'lodash';
_.find(carBrands, car1); //returns object if true, undefined if false
Working Plunker using this method: https://plnkr.co/edit/y2YX9o7zkQa2r7lJ
if its possible to use es6
carBrands.filter(carBrand => carBrand.name === carX.name).length > 0
if it's true there is a similarity
You can convert both the JSON objects to string and simply check if the bigger json contains the smaller json.
console.log(JSON.stringify(carBrands).includes(JSON.stringify(car1))); // true
console.log(JSON.stringify(carBrands).includes(JSON.stringify(car5))); // false
You could also a the findIndex
var carBrands = [];
var car1 = {name:'ford'};
var car2 = {name:'lexus'};
carBrands.push(car1);
if (carBrands.findIndex(f => f.name === car1.name) === -1) {
console.log('not contain')
} else {
console.log('contain')
}
if (carBrands.findIndex(f => f.name === car2.name) === -1) {
console.log('not contain')
} else {
console.log('contain')
}

Categories

Resources