I have a nested object like so:
var depositOptions = {
0 : {name: 'Monthly'},
1 : {name : 'Standard'},
2 : {name: 'Full' },
3 : {name: 'Low' }
};
I need to remove the object where name = 'Standard' so I'm iterating over it using Underscore.js _.each until I find it, and storing the index.
_.each(depositOptions, function(option, i) {
if (option.name === 'Standard') {
// delete the object at index i
console.log(i)
}
});
So I want to remove the option when it finds standard - what is the easiest way to do this?
1) Remove it inside the _.each loop, when standard is found? (Therefore no need for the index)
2) Store the index of the object I want to remove, and then delete it after I've finished iterating? (This I am finding difficult because how do I get the index outside of the loop?)
3) Start creating a new array as I iterate over depositOptions so that a new array is built without standard included
When I say I want to delete it, I want it completely gone. So not just undefined like using delete does.
Use _.filter or _.reject instead. It wouldn't be clear to use _.each. Notice that these return a new array.
var newArray = _.filter(depositOptions, function(option) {
return option.name !== 'Standard';
});
Also it looks like you have an object, not an array. Here is an array:
var depositOptions = [
{name: 'Monthly'},
{name : 'Standard'},
{name: 'Full' },
{name: 'Low' }
];
You can use the _.without function to eliminate the key which you don't need
var depositOptions = {
0 : {name: 'Monthly'},
1 : {name : 'Standard'},
2 : {name: 'Full' },
3 : {name: 'Low' }
};
depositOptions = _.without(depositOptions, _.findWhere(depositOptions, {
name: 'Standard'
}));
console.log(depositOptions);
Hope this helps!.
If you want to return new object with filtered properties you can use Object.keys() and reduce() in plain javascript.
var depositOptions = {
0 : {name: 'Monthly'},
1 : {name : 'Standard'},
2 : {name: 'Full' },
3 : {name: 'Low' }
};
var result = Object.keys(depositOptions).reduce(function(r, k) {
if (depositOptions[k].name != 'Standard') r[k] = depositOptions[k]
return r;
}, {})
console.log(result)
According to me the best way to do that using underscore is _reject.
Usage -
_.reject(depositOptions, function(val){ return val.name == 'Standard'; });
Option 3 is definitely not an option because you using exclusion method, where you are trying to fetch all other elements apart from the one you want & make use of the element you want. Too dirty for your implementation!
Option 2 is better than option 3 but not ideal because you have found the element & your still wasting your time iterating over others
Option 1 with a tweak is the best solution from the options given - small tweak includes add a break statement within the if statement & after you store the element. This way your just iterating till you find the element.
You have 2 options, you either mutate your original object or you create a new object without the unwanted key-value pair. All examples are in plain ES6, but you can easily use lodash methods. They will exclude all matches not just the first match.
Mutation. Uses for..of and Object.keys
const depositOptions = {
0: {
name: 'Monthly'
},
1: {
name: 'Standard'
},
2: {
name: 'Full'
},
3: {
name: 'Low'
}
};
for (let key of Object.keys(depositOptions)) {
if (depositOptions[key].name === 'Standard') {
delete depositOptions[key];
}
}
console.log(depositOptions);
Create new object without the reference to the unwanted object.
const depositOptions = {
0: {
name: 'Monthly'
},
1: {
name: 'Standard'
},
2: {
name: 'Full'
},
3: {
name: 'Low'
}
};
const depositOptionsFiltered = {};
for (let key of Object.keys(depositOptions)) {
if (depositOptions[key].name !== 'Standard') {
depositOptionsFiltered[key] = depositOptions[key];
}
}
console.log(depositOptionsFiltered);
You may even want a new object and the key-value object to be a copy of the original rather than references to them. In this case you can perform a shallow copy. Uses Object.assign
const depositOptions = {
0: {
name: 'Monthly'
},
1: {
name: 'Standard'
},
2: {
name: 'Full'
},
3: {
name: 'Low'
}
};
const depositOptionsFiltered = {};
for (let key of Object.keys(depositOptions)) {
if (depositOptions[key].name !== 'Standard') {
depositOptionsFiltered[key] = Object.assign({}, depositOptions[key]);
}
}
console.log(depositOptionsFiltered);
Related
There are just 2 objects in an array where I need your attention at. I'm trying to find a way to merge these two objects into a single object based on item.Symbol and then add the values of their corresponding item.TotalCost, item.Price, and item.Quantity to the new object.
I tried doing a Set function but they just merge into 1 object and the values aren't added. I'm receiving an object like this:
[{
CompanyName: "Microsoft Corp."
Date: 1606503905
Price: 215.23
Quantity: 50
Symbol: "MSFT"
TotalCost: 10761.5
},
{
CompanyName: "Microsoft Corp."
Date: 1606503913
Price: 215.23
Quantity: 25
Symbol: "MSFT"
TotalCost: 5380.75
}
]
Here is my code so far:
let set = new Set()
const newSet = Objects.filter(item => {
if (!set.has(item.Symbol)) {
set.add(item.Symbol)
return true;
}
return false},set
)
console.log(newArray)
Note that the Objects variable contains the array of objects shown in the first code block.The set function I wrote only merges them into a single object based on their Symbol but I don't know where to go from here. I'm praying to the Javascript Overlords and Es6 Sith Lords to heed my call. May the force be with you.
Reduce the array of objects to an object, using the Symbol property as the key. If the key doesn't exist on the object, assign a clone of the current item to the key. If it exists, add the current item's values to the existing object:
const arr = [{"CompanyName":"Microsoft Corp.","Date":1606503905,"Price":215.23,"Quantity":50,"Symbol":"MSFT","TotalCost":10761.5},{"CompanyName":"Microsoft Corp.","Date":1606503913,"Price":215.23,"Quantity":25,"Symbol":"MSFT","TotalCost":5380.75}]
const newArray = Object.values(
arr.reduce((acc, o) => {
if(!acc[o.Symbol]) acc[o.Symbol] = { ...o }
else {
acc[o.Symbol].Price += o.Price
acc[o.Symbol].Quantity += o.Quantity
acc[o.Symbol].TotalCost += o.TotalCost
}
return acc
}, {})
);
console.log(newArray)
I have a huge nested JSON object, and need to find a specific one by a certain value of a certain key.
For example:
[ {
id: 't53',
action: 'Boot',
time: 2019-04-21T17:58:34.579Z
},
{
id: 't54',
action: 'Reset',
time: 2019-04-24T17:57:33.549Z
} ]
So, if need to find the object where action is Boot, and the result must be:
{
id: 't54',
action: 'Boot',
time: 2019-04-24T17:57:33.549Z
}
You can use the Array.find method to get the first item that matches the condition.
const item = objs.find(obj => obj.action === 'Boot');
If you want to find the first element from last, you could create a shallow copy of the array and reverse it.
const item = objs.slice().reverse().find(obj => obj.action === 'Boot');
var data = [{
id: 't53',
action: 'Boot',
time: '2019-04-21T17:58:34.579Z'
},
{
id: 't54',
action: 'Boot',
time: '2019-04-24T17:57:33.549Z'
}];
var result = data.filter(a => a.action === 'Boot');
console.log(result);
You loop over the array and check each item action key is you want or not.
Trying to learn a concept.
If I have Object of keyed objects and an array of keys.
const orders = {
"key1" : { id: "key1", number: "ORD001" },
"key3" : { id: "key3", number: "ORD003" },
"key2" : { id: "key2", number: "ORD002" },
};
and an array:
const selectedOrders = ["key1","key2"];
and with the help of Redux Reselect. I want to have a new object like:
const orders = {
"key1" : { id: "key1", number: "ORD001" selected: true},
"key3" : { id: "key3", number: "ORD003" selected: false },
"key2" : { id: "key2", number: "ORD002" selected: true },
};
So later I can iterate over that object via Object.keys(this.orders) and style selected items.
Is this correct to use Reselect for such use-case? If yes, then how should I check-in an efficient and idiomatic way, does an external array contains a given key?
If this idea is totally wrong for such use-case, then how should I do that in the right way?
Addendum: There also could be another array which contains keys in sequence how those orders should be displayed. (User is able to reorder items).
P.S. I don't want to use an array of objects for orders collection.
Yes, you can use reselect to combine two sets of data to produce a third set. Due to reselect's memoization, if the inputs don't change, then the calculation only needs to be performed once.
// You'll need some input selectors to pluck the raw orders from your redux store.
// I'm making these up, since i don't know how your store is arranged.
const getOrders = (state) => state.orders;
const getSelectedOrders = (state) => state.selectedOrders;
const getAugmentedOrders = createSelector(
[getOrders, getSelectedOrders],
(orders, selectedOrders) => {
const augmentedOrders = {};
Object.keys(orders).forEach(key => {
augmentedOrders[key] = {
...orders[key],
selected: selectedOrders.includes(key),
}
});
return augmentedOrders;
}
);
If you have a lot of selected orders, then doing selectedOrders.includes every time through the loop may be a performance problem. In that case i'd create a Set of the selectedOrders, since lookups into the Set will be constant time.
(orders, selectedOrders) => {
const selectedSet = new Set(selectedOrders);
const augmentedOrders = {};
Object.keys(orders).forEach(key => {
augmentedOrders[key] = {
...orders[key],
selected: selectedSet.has(key),
}
});
return augmentedOrders;
}
I have an underscore filter which is returning the parent object which contains a child object I am looking for. But I want it to return just the child object. Since it is already doing the work of locating the child object in order to return the parent, I'm wondering how to simplify my code to return just the child. Here's the example:
var filterObj = _.filter(filtersPath, function(obj) {
return _.where(obj.filters, {id: prefilterCat}).length > 0;
});
So here, that nested object inside obj.filters, with the id of prefilterCat, is the object I want returned, not its parent. So currently I would have to do another find inside of filterObject to get what I need. Any ideas?
Underscore's filter method will return the "parent" object but will filter out the ones that don't match the conditional statement. That being the case, if there is only 1 result, then you can just access it similarly to how you would access an array. For instance:
var filterObj = _.filter(filtersPath, function(obj) {
return _.where(obj.filters, {id: prefilterCat}).length > 0;
})[0];
The above example would get the first child that is returned from the filter method.
From your question and code, I'm assuming a data structure like this:
var filtersPath = [
{
filters: [
{id: 0},
{id: 1}
]
},
{
filters: [
{id: 5},
{id: 42}
]
}
];
Now you can get an array of all "parent objects" (which you already have done) that have a filters array containing a object with matching ID:
_.filter(filtersPath, function(obj) {
return _.find(obj.filters, { id: 5 });
});
The advantage of doing it this way is that it will stop searching for a value once it's found one, and not always traverse the entire list.
If you want to actually get an array as result, it's a simple map operation:
_.chain(filtersPath)
.filter(function(obj) {
return _.find(obj.filters, { id: 5 });
})
.map(function(obj) {
return obj.filters;
})
.value();
If you only want to get the first matching object, you don't even need to use a filter or map:
_.find(filtersPath, function(obj) {
return _.find(obj.filters, { id: 5 });
})
.filters;
With lo-dash, this operation will be a little easier:
_.find(filtersPath, { filters: [{ id: 5 }] }).filters
I am trying to acheive something similar to SQL table join,
in the most elegant (functional) way, preferably with underscore.js,
so no for loops please.
I need to merge objects from two different arrays, matched upon a common identifier.
For example, given:
var basic = [{
id: '1',
name: 'someName',
},
{...} ]
var ext= [{
id: '1',
job: 'someJob',
},
{...} ]
Result should be:
var combined = [{
id: '1',
name: 'someName',
job: 'someJob',
},
{...} ]
Thanks!
Map, findWhere and extend should do the trick:
var combined = _.map(basic, function(base){
return _.extend(base, _.findWhere(ext, { id: base.id} ));
});
Edit:
If performance is an issue create a hash of the extended values:
var extHash = _.reduce(ext, function(memo, extended, key){
memo[extended.id] = extended;
return memo;
}, {});
and use like so:
var combined = _.map(basic, function(base){
return _.extend(base, extHash[base.id]);
});
Fiddle
NO LOOP : http://jsfiddle.net/abdennour/h3hQt/2/
basic=basic.sort(function(a,b){return a.id-b.id});
ext=ext.sort(function(a,b){return a.id-b.id});
var combined=basic.map(function(e,i){return inherits(e,ext[i]) });
Known that ,inherits are as following:
function inherits(base, extension)
{
for ( var property in base )
{
extension[property] = base[property];
}
return extension ;
}