Using LoDash to map over an object:
_.map(items, (item) = > {
if (Array.isArray(item)) {
// don't include this in final object
}
return _.assign({
foo: "bar"
}, item);
});
Wondering what my best tactic is for not including an object in the returned, mapped, object if the current object is an array?
You may use reduce which works perfectly for your case:
var items = [{a: 1}, ["asd"], {b: 2}];
var result = _.reduce(items, (res, item) => {
if (!Array.isArray(item)) {
_.assign(res, item);
}
return res;
}, {foo: "bar"});
See jsbin.
Another (and IMO a cleaner) solution is to use chaining:
results = _(items).reject(_.isArray).map(function(item) {
....
}).value()
I would expect a map function to always output the same keys as the input. The values maybe modified, but the keys remain the same.
There are other functions you can use to change the set of items like filter or some kind of aggregate or reduce.
This... just assign an empty object if item is an array, otherwise assign item:
_.map(items, (item) = > {
return _.assign({
foo: "bar"
}, Array.isArray(item)?{}:item);
});
Here's a little fiddle without the new anonymous function syntax: https://jsfiddle.net/xurm6vrr/1/
Related
Here is my example. I have an object in Javascript that is dynamically changed.
And I want in this case the value of the property "inside" and I know that the value is in the place a[something][anotherthing][inside]. Because I saved the position in an array ["a","somethig", "anotherthing"]. my question is How do I move to that position using the keys that are in the array?. Already tried to concat the elements and the final result is something like this myObject[a][somthing][anotherthing] but the problem is that it returns 'undefined' because it's a string. Is there any chance to convert it to object or some way to get that position in the object?
var myarray = ['a', 'something', 'anotherthing'];
myObject = {
a: {
something: {
anotherthing: {
inside: 10
}
}
},
b: {
insideb: {}
}
}
Use reduce to reduce the array to a single value. You will pass in myObject as the starting point (second parameter), then use this basic callback (first parameter):
(obj, itm) => obj[itm]
When you put it all together, it will look like this:
var myarray = ['a', 'something', 'anotherthing'];
myObject = {
a: {
something: {
anotherthing: {
inside: 10
}
}
},
b: {
insideb: {
}
}
}
let result = myarray.reduce((obj, itm) => obj[itm], myObject)
console.log(result)
console.log(result.inside)
If you know the exact location of the value: myObject['a']['somthing']['anotherthing'] will give you the value.
If you need to step through the object dynamically, you can use: Object.keys(myObject).forEach(key => myObject[key]); to get the top level keys.
I have an array of objects that looks something like
{
"foo":[
{
"bar":"boo"
},
{
"baz":"bang"
}
]
}
I want to update baz with a new value but I cannot work out how to merge both these objects?
I tried something like Object.assign({}, foo,{baz: 'beep'})
But this did not work?
foo is an Array of objects to replace it with new value, try the following:
var obj = { "foo":[ { "bar":"boo" }, { "baz":"bang" } ] };
var index = obj.foo.findIndex((o) =>Object.keys(o).includes("baz"));
if(index != -1)
Object.assign(obj.foo[index], {baz: 'beep'});
console.log(obj);
Assuming you don't necessarily know the array index of the element you're trying to modify, you'll need to search through that array to find it -- for example using Array.find():
let quux = {
"foo":[
{
"bar":"boo"
},
{
"baz":"bang"
}
]
}
quux.foo.find(
(obj) => {
return obj.baz === "bang"
}
).baz="beep";
console.log(quux);
// This mutates the original object; if you need a clone wrap this in an Object.assign as shown in other answers
(Arrays of objects can be inconvenient for this reason; you may be better off with an object of objects, so there's an ID for each.)
If you're trying to create a modified copy of foo, use Array.prototype.map:
const foo = [
{
"bar":"boo"
},
{
"baz":"bang"
}
];
const newFoo = foo.map(value => {
if('baz' in value) return Object.assign({}, value, {a: 'b'});
return value;
});
console.log(newFoo);
I'm trying to duplicate key-value pairs from one object into each distinct object inside an array.
const propsToDuplicate = {
foo: 'foo',
bar: 'bar'
};
const items = [{
num: 1
},
{
num: 2
}
];
const result = items.map(item => {
console.log('item: ', item);
const moar = Object.assign(propsToDuplicate, item);
console.log('item with more stuff: ', moar);
return moar;
});
console.log(result);
Questions:
Why do I end up with two instances of the object with num = 2?
How can I perform this operation so that the final result is as below?
Desired result:
[ { foo: 'foo', bar: 'bar', num: 1 },
{ foo: 'foo', bar: 'bar', num: 2 } ]
Here is the sandbox:
https://repl.it/#montrealist/array-map-and-object-assign-weirdness
Object.assign(a, b, c) will assign everything from a, b, and c into the object that is the first parameter to assign().
In your case you are using propsToDuplicate as the first parameter, and this means that that each time assign() is called, propsToDuplicate is being mutated.
Change const moar = Object.assign(propsToDuplicate, item); to const moar = Object.assign({}, propsToDuplicate, item); and you should be good to go.
Why do I end up with two instances of the object with num = 2
because moar === propsToDuplicate in your code. You've assigned all these properties/values to the very same object. And all indices of that array reference the same object.
How can I perform this operation so that the final result is as below?
assign the properties to an empty object:
const morar = Object.assign({}, propsToDuplicate, item);
The workaround is to return JSON.parse(JSON.stringify(moar));
this doesn't really work, as you still assign all the properties into the same object, but you return a snapshot of each iteration. If you add another property only to the first object in items you'll see it show up for the other(later) items as well.
Plus JSON.parse(JSON.stringify(...)) is a ugly approach to clone an object.
Or I could simply flip the parameters - would this work? Object.assign(item, propsToDuplicate);
yes/no/kind of/better not ... I have to explain.
In that case, you'll overwrite the properties in item with the properties in propsToDuplicate, and you'd mutate the objects in the items array. In your current code this would make no difference, but if some item would have a foo or bar property or if propsToDuplicate would contain a num, you'd overwrite that property in the result.
explaining that: Object.assign() is often used to compose some config object with some default values.
let options = Object.assign({}, defaults, config);
this will take an empty Object, then first write all the default values into that and then overwrite soem of the default values with the values passed in the config.
whereas
let options = Object.assign(config, defaults);
will overwrite all the custom configutations with the default values.
Then there's the problem of mutation. The problem with mutation is that depending where you got the object from, and where else it is referenced, you changing the object may introduce errors at the other end of your application, in some completely unrelated peice of code. And then have fun debugging that and finding the error.
I am looking for a short and efficient way to filter objects by key, I have this kind of data-structure:
{"Key1":[obj1,obj2,obj3], "Key2":[obj4,obj5,obj6]}
Now I want to filter by keys, for example by "Key1":
{"Key1":[obj1,obj2,obj3]}
var object = {"Key1":[1,2,3], "Key2":[4,5,6]};
var key1 = object["Key1"];
console.log(key1);
you can use the .filter js function for filter values inside an object
var keys = {"Key1":[obj1,obj2,obj3], "Key2":[obj4,obj5,obj6]};
var objectToFind;
var keyToSearch = keys.filter(function(objects) {
return objects === objectToFind
});
The keyToSearch is an array with all the objects filter by the objectToFind variable.
Remember, in the line return objects === objectToFind is where you have to should your statement. I hope it can help you.
You can create a new object based on some custom filter criteria by using a combination of Object.keys and the array .reduce method. Note this only works in es6:
var myObject = {"Key1":["a","b","c"], "Key2":["e","f","g"]}
function filterObjectByKey(obj, filterFunc) {
return Object.keys(obj).reduce((newObj, key) => {
if (filterFunc(key)) {
newObj[key] = obj[key];
}
return newObj;
}, {});
}
const filteredObj = filterObjectByKey(myObject, x => x === "Key1")
console.log(filteredObj)
Not sure what exactly are you trying to achieve, but if you want to have a set of keys that you would like to get the data for, you have quite a few options, one is:
var keys = ['alpha', 'bravo'];
var objectToFilterOn = {
alpha: 'a',
bravo: 'b',
charlie: 'c'
};
keys.forEach(function(key) {
console.log(objectToFilterOn[key]);
});
I have a structure like this:
var myMap = {
partnr1: ['modelA', 'modelB', 'modelC'],
partnr2: ['modelA', 'modelB', 'modelC']
};
I am going to iterate through each of the elements (partnr) with their associatives (models).
I am trying a double $each() iteration in order to achieve this, but nothing happens:
$.each(myMap, function (i, val) {
$.each(i, function (innerKey, innerValue) {
setTimeout(function () {
$('#variant').fadeOut("slow", function () {
$(this).text(innerKey + "-" + innerValue).fadeIn("slow");
});
}, i * 6000);
});
});
The effect with fading in and out that I am trying to achieve is working fine when using a single value array (Object), but not when I need to have more than one value for each key like here.
How to accomplish this iteration successfully? Are there other ways than using an Object that would be better in this case?
An answer to your Question from 2019:
It depends on what version of ECMAScript you use.
Pre ES6:
Use any of the answers below, e.g.:
for (var m in myMap){
for (var i=0;i<myMap[m].length;i++){
... do something with myMap[m][i] ...
}
}
For ES6 (ES 2015):
You should use a Map object, which has the entries() function:
var myMap = new Map();
myMap.set("0", "foo");
myMap.set(1, "bar");
myMap.set({}, "baz");
for (const [key, value] of myMap.entries()) {
console.log(key, value);
}
For ES8 (ES 2017):
Object.entries() was introduced:
const object = {'a': 1, 'b': 2, 'c' : 3};
for (const [key, value] of Object.entries(object)) {
console.log(key, value);
}
I'd use standard javascript:
for (var m in myMap){
for (var i=0;i<myMap[m].length;i++){
... do something with myMap[m][i] ...
}
}
Note the different ways of treating objects and arrays.
Functional Approach for ES6+
If you want to take a more functional approach to iterating over the Map object, you can do something like this
const myMap = new Map()
myMap.forEach((value, key) => {
console.log(value, key)
})
Well, it looks like this old JQuery thread has been coopted by ES6 Map users.
If this is what you're looking for, may I suggest using the Array.from() function which converts the Map to an Array. This allows you to easily chain transforms such as filter(), map(), etc.
const map = new Map([
['key one', 'value one'],
['key two', 'value two'],
]);
// Loop through key-value-pairs
Array.from(map.entries()).map(([key, val]) => console.log(key, val));
// Loop through map keys
Array.from(map.keys()).map(key => console.log(key));
// Loop through values
Array.from(map.values()).map(value => console.log(value));
The callback to $.each() is passed the property name and the value, in that order. You're therefore trying to iterate over the property names in the inner call to $.each(). I think you want:
$.each(myMap, function (i, val) {
$.each(val, function(innerKey, innerValue) {
// ...
});
});
In the inner loop, given an object like your map, the values are arrays. That's OK, but note that the "innerKey" values will all be numbers.
edit — Now once that's straightened out, here's the next problem:
setTimeout(function () {
// ...
}, i * 6000);
The first time through that loop, "i" will be the string "partnr1". Thus, that multiplication attempt will result in a NaN. You can keep an external counter to keep track of the property count of the outer map:
var pcount = 1;
$.each(myMap, function(i, val) {
$.each(val, function(innerKey, innerValue) {
setTimeout(function() {
// ...
}, pcount++ * 6000);
});
});
Don't use iterators to do this. Maintain your own loop by incrementing a counter in the callback, and recursively calling the operation on the next item.
$.each(myMap, function(_, arr) {
processArray(arr, 0);
});
function processArray(arr, i) {
if (i >= arr.length) return;
setTimeout(function () {
$('#variant').fadeOut("slow", function () {
$(this).text(i + "-" + arr[i]).fadeIn("slow");
// Handle next iteration
processArray(arr, ++i);
});
}, 6000);
}
Though there's a logic error in your code. You're setting the same container to more than one different value at (roughly) the same time. Perhaps you mean for each one to update its own container.
We can use forEach Method available on maps From ES6 Version.
var myMap =new Map([
["partnr1", ['modelA', 'modelB', 'modelC']],
["partnr2", ['modelA', 'modelB', 'modelC']]
]);
myMap.forEach(function(values,key){
console.log(key);
/*****Do something with the models***********/
for(const [index,value] of values.entries()){
console.log(` ${key}[${index}] : ${value}`);
}
});
This is easily achieved using a javascript Map object. You simply iterate over the Map, using the fact that the map you're iterating over is included as an argument in each iteration call. Notice the map argument in the forEach function. This is the same Map object you're iterating over.
// Define the map
const myMap = new Map([
["key1", "value 1"],
["key2": "value 2"],
["key3": "value 3"]
])
// Iterate over the map, updating each value
myMap.forEach((value,key,map) => {
map.set(key, value + "A")
})
/*
Result: myMap now looks like this:
[
["key1", "value 1A"],
["key2": "value 2A"],
["key3": "value 3A"]
]
/*