I have an object in key/value pairs that may contain boolean values. I need to evaluate the type of the value so I know what to return. So let's say I have an object that looks like:
{
aKey: false,
anotherKey: 4,
yetAnotherKey: true
}
I want to loop through each key/value pair there and do something different depending on the type of the value. If I use Object.keys(options).map((key, index), it transforms the boolean values from true/false to 0/1, so I have no way of knowing that those are actually booleans.
What is the best way to go about this?
I think you just "oopsied" - you haven't even checked the value of the options object in your map function. The second parameter provided to an Array#map callback is always the index.
Extending your code to check the type of the value in options:
Object.keys(options).map((key, i, all_keys) => {
let val = options[key];
console.log(typeof val)
...
});
Consider reviewing the different methods of iteration / enumeration in JavaScript, e.g.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Loops_and_iteration
How to iterate over a JavaScript object?
Your .map(key, index) is looping over the array ["aKey", "anotherKey", "yetAnotherKey"] and losing the values in options. Maybe something like this would work for you:
for( o in options ){
console.log(o, options[o])
}
> aKey false
> anotherKey 4
> yetAnotherKey true
Related
In Javascript I have a collection of objects, whose values I'm storing in variable
var filters = {
BeginDate: $("#BeginDateRange").val(),
EndDate: $("#EndDateRange").val(),
ListOfCodes: $("#ListOfCodes").val(),
//ListOfCodes: $("#ListOfCodes").val().join(),
...
}
Based on where I use the collection, some of its objects remain 'undefined', and it is intended.
ListOfCodes above is an array of string values, and I want to pass it to the binder as a single comma-separated string (e.g ["1"], ["2"] -> "1,2")
I was able to make a use of .join(), and it worked successfully. However, I found later that the code will crash if the .join() does not have a value to join.
Is there a way to apply .join() INSIDE the collection to the variable ONLY if it has value? Something like
var filters = {
BeginDate: $("#BeginDateRange").val(),
EndDate: $("#EndDateRange").val(),
ListOfCodes: if( $("#ListOfCodes").val() )
{$("#ListOfCodes").val().join()}
else
{$("#ListOfCodes").val()} //value remains undefined
,
...
}
EDIT: I ask about the possibility of applying .join() method inside the collection, not checking for empty values.
Just moving this as an answer.
What about a ternary statement?
ListOfCodes: ($("#ListOfCodes").val()) ? $("#ListOfCodes").val().join() : null
I'm trying to understand how to iterate through this simple array.
var data = [{"blahh":"hi","blah2":"333","third":"920","fourth":"800"}];
What I am trying to accomplish is, appending an object that is the sum of certain keys (the 'third' and 'fourth')...resulting data being this:
var data = [{"blahh":"hi","blah2":"333","third":"920","fourth":"800", "sum": "1720"}];
I imagine 'lodash' library is capable of neatly accomplishing this. I just can't figure out how to pull that off. I know this is a newbie question but perhaps answering it may helps some soul better understand lodash.
As mentioned - you don't need lodash for this. You're looking at the map function to iterate over an array and return a new array (in this case an array of objects returning a new array with objects that have a sum property) and reduce to iterate over all desired keys and sum their values. For example:
//If you want to treat numbers as numbers then use numbers.
//Some answers here are coercing strings with + - however this will result in NaN on non coerceable strings -ie 'hello',
//which will cause unexpected errors for you later (and typeof NaN is number)
var data = [{"blahh":"hi","blah2":333,"third":920,"fourth":800}];
function returnNewArrayWithSums(keys, array) {
return array.map(obj => {
obj.sum = keys.reduce((sum, key) => typeof obj[key] === 'number' ? obj[key] + sum : sum, 0);
return obj;
});
}
returnNewArrayWithSums(['third', 'fourth'], data);
edited to add - this answer is to give you a use case w/ map/reduce - ideally you wouldn't have to specify numeric keys and make this function more general for any arrays that have objects with k/v pairs that are nums that you want to sum
No need for a library to do this ... the code will likely be more complicated looking than using native methods
data.forEach(item){
item.sum = (+item.third || 0) + (+item.fourth || 0);
});
You have an array of one object - which I dont think you are trying to do. Arrays do not have a key:value pair in them (well actually they do in JavaScript but ignore that). They are an indexed list of values. You probably want to do something like this:
// notice im not putting the integer values in quotes
var data = {'blah':'hi', 'blah2':333, 'third':920, 'fourth':800 };
data.sum = data.third + data.fourth;
That will add a 'sum' field to your object with the value of the sum of third and fourth. Is this what you are trying to do?
I have an array of json objects who results I want to groupBy() based on multiple properties i.e.,
I have:
[
{
prop1:val1,
prop2:val2,
prop3:val3,
prop4:val4
}
]
Now if I just wanted to group by prop1 I guess I could have done :
_.groupBy(givenArray, 'prop1');
Now what should I do if I have to group by prop1,prop2 and prop3, i.e., (prop1 && prop2 && prop3)
Please guide.
You can put that target values to an array, and then form them to string, or just transform them to string form and combine:
_.groupBy(givenArray, function(item) {
var keys = _.pick(item, 'prop1', 'prop2', 'prop3');
// If all are string or number,
// return keys.join('_#%#_'); // this prevent ['ab', 'a'] generate same key to ['a', 'ba'];
return JSON.stringify(keys);
});
JSON.stringify maybe one of the many ways to create a combined key, I'm not sure what your vals is (string, number or else), so I'll just use stringify here.
It really depends on what you want your final structure to be.
If you don't mind a non-flat object structure, you can do nested _.groupBy calls:
var result = _(givenArray) //begin chain
.groupBy('a')
.mapValues(function(groupedByA) {
return _(groupedByA) //begin chain
.groupBy('b')
.mapValues(function (groupedByAAndB) {
return _.groupBy(groupedByAAndB, 'c');
})
.value(); //end chain
})
.value(); //end chain
//Then you can do things like:
result[5][4][3]; //All items where a=5, b=4, and c=3.
Downside here is that there's an extra level of nesting for each property you group by, and result[5][4] will blow up if there aren't any results where a=5 for example. (Though you could use a library like koalaesce for that)
Alternatively, if you want a flat object structure, but don't mind it being a bit ungainly to access the items, then:
var result = _.groupBy(givenArray, function (item) {
return JSON.stringify(_.pick(item, 'a','b','c'));
});
//Much simpler above, but accessed like:
result[JSON.stringify({a: 5, b:4, c:3})]
Much simpler and scales better to grouping by more things... but awkward to work with, since the keys are full JSON strings; but then you also don't have the null issue that the first option has.
You can also, just use _.values or some equivalent to turn the flat object structure into a single array of arrays. Then there's obviously no "random" access to get all items with a given value of a,b, and c, but you can always loop over it.
I'm working on JavaScript and I have this JSON object:
var obj ={"name" : "objName",
"dynamicList" :[]};
and then I add some items to my list like this:
obj.dynamicList["someStringID"] = {"watever"};
It's important that I use a string as indexer for each item on my list (i didn't know this could be done until recently).
My only problem now is that whenever I ask for obj.dynamicList.lenght I get 0, unles I manually set the proper number... I was wondering if there's a better way to add items to my list?
Thanks!!
In Javascript, string index is not really an index. It's actually an attribute of the array object. You could set and get the value with the string index, but it's actually an empty array with some attributes. Not only .length, but also .sort(), .splice(), and other array function would not work. If there is a need to use array functions, I would use number as an index to make it a real item in the array.
If you have to use the string as an index, you couldn't rely on .length function. If there is no need to support IE prior to version 9, the Object.keys as suggested by #strimp099 should work. or you may have to create function to count the number of attributes for example:
function len(obj) {
var attrCount = 0;
for(var k in obj) {
attrCount++;
}
return attrCount;
}
and then call
len(obj.dynamicList);
Use the following the find the length of dynamicList object:
Object.keys(obj.dynamicList).length
To do this "the right way," you will have to make obj.dynamicList an object instead of an array; use {} instead of [] to set the initial value.
How to efficiently count the number of keys/properties of an object in JavaScript?
dynamiclist is an object, the length is not the length property you expect from an array.
In the following code why the variable 'a' refer to the index rather than the value ?
for (var a in Values) {
alert(Values[a]);
}
That's by design. It's trivial to get a value in an array when you know its key, but it's much harder to get a key given a value. Values can be duplicated, so how do you know which key should be used? But a key's unique, so given a key, there's only ever one value to retrieve. So, the for loop will iterate over the keys, and it's trivial to get the associated value.
Think of a JavaScript Array as a normal Object with a special property named length (actually, it a bit more complex). So the for..in loop behaviour is identical as for other objects:
var a = new Array();
a[1] = "a";
alert(a.length); // 2
alert(a[0]); // undefined
a[1000] = "b"
alert(a.length); // 1001
a[-1] = "c";
alert(a[-1]); // c
a.abc="why not";
for(var key in a)
{
alert(key+"="+a[key]);
}
// 1=a
// 1000=b
// -1=c
// abc=why not
Also note that you can have gaps within your array without having to pay the memory price.
There is a for each...in loop that does exactly that - enumerates only values. Coming soon to a browser near you.
for each(var a in Values) {
..
}
For arrays, there is a new function forEach which achieves the same.
someArray.forEach(function(value) {
..
});