how to assign a key in object using javascript - javascript

I want to total all same ID and assign a specific key
var ingredArray= [{"inventory_id":1,"pergram":222},{"inventory_id":1,"pergram":33},{"inventory_id":2,"pergram":424},{"inventory_id":2,"pergram":22},{"inventory_id":3,"pergram":400},{"inventory_id":5,"pergram":200}]
let deduction={};
ingredArray.forEach(function (item) {
if (deduction.hasOwnProperty(item.inventory_id)) {
deduction[item.inventory_id] = deduction[item.inventory_id] + parseFloat(item.pergram);
} else {
deduction[item.inventory_id] = parseFloat(item.pergram);
}
});
console.log(deduction);
this is the result of my code
{1: 255, 2: 446, 3: 400, 5: 200}
I want to achieve
{"inventory_id":1,"pergram":255},{"inventory_id":2,"pergram":446},{"inventory_id":3,"pergram":400},{"inventory_id":5,"pergram":200}

Try this
var ingredArray = [{ "inventory_id": 1, "pergram": 222 }, { "inventory_id": 1, "pergram": 33 }, { "inventory_id": 2, "pergram": 424 }, { "inventory_id": 2, "pergram": 22 }, { "inventory_id": 3, "pergram": 400 }, { "inventory_id": 5, "pergram": 200 }]
var helper = {};
let deduction = ingredArray.reduce(function (r, o) {
var key = o.inventory_id;
if (!helper[key]) {
helper[key] = Object.assign({}, o); // create a copy of o
r.push(helper[key]);
} else {
helper[key].pergram += o.pergram;
}
return r;
}, []);
console.log(deduction);

reduce over the array of objects building a new object of summed values based on key, and then grab the Object.values.
const data = [{"inventory_id":1,"pergram":222},{"inventory_id":1,"pergram":33},{"inventory_id":2,"pergram":424},{"inventory_id":2,"pergram":22},{"inventory_id":3,"pergram":400},{"inventory_id":5,"pergram":200}];
const out = data.reduce((acc, c) => {
// Grab the id and pergram variables from the
// new object in the iteration
const { inventory_id: id, pergram } = c;
// If the the accumulator object doesn't have a key that
// matches the id create a new new object, and set the
// pergram variable to zero
acc[id] = acc[id] || { inventory_id: id, pergram: 0 };
// And then add the pergram value to the
// pergram object property
acc[id].pergram += pergram;
// Return the accumulator for the next iteration
return acc;
}, {});
console.log(Object.values(out));

Use Map to store the object reference based on unique inventory_id and call Array.reduce() method over list of objects.
var ingredArray= [{"inventory_id":1,"pergram":222},{"inventory_id":1,"pergram":33},{"inventory_id":2,"pergram":424},{"inventory_id":2,"pergram":22},{"inventory_id":3,"pergram":400},{"inventory_id":5,"pergram":200}];
const processArray = (list) => {
const map = new Map();
return list.reduce((accumulator, obj) => {
const inventory = map.get(obj.inventory_id);
if (inventory) {
inventory.pergram += obj.pergram;
} else {
accumulator.push(obj);
map.set(obj.inventory_id, obj);
}
return accumulator;
}, []);
}
console.log(processArray(ingredArray));

Related

Generated a Nested Object from TLV

I am trying to parse a TLV string and need to generate a nested object from that string.
const text = 'AA06ClaireCC04JackBB03TomEE05James'
The output needs to look like this:
"Acrobatic Artist": {
"AA": {
"Claire": {
"Curious Camper": {
"CC": {
"Jack": {
"Baddest Banana": {
"BB": {
"Tom": {
"Energetic Elephant": {
"EE": {
"James" : "LASTRECORD"
}
}
}
}
}
}
}
}
}
}
}
Here is what I currently have:
const map = {
AA: 'Acrobatic Artist',
BB: 'Baddest Banana',
CC: 'Curious Camper',
DD: 'Desperate Driver',
EE: 'Energetic Elephant'
}
function createJson(str) {
let json = {}
let remainingText = str
while(remainingText.length > 0) {
const tag = remainingText.substring(0, 2)
const len = remainingText.substring(2, 4)
const val = remainingText.substring(4, len)
const offset = tag.length + len.length + parseInt(len, 16)
remainingText = remainingText.substring(offset)
console.log('new text: ' + remainingText)
json[map[tag]] = {}
json[map[tag]][tag] = {}
json[map[tag]][tag][val] = {}
}
return json
}
But this just creates an object that looks like this:
{
Acrobatic Artist: {
AA: {
Claire: {}
}
},
Baddest Banana: {
BB: {
Tom: {}
}
},
Curious Camper: {
CC: {
Jack: {}
}
},
Energetic Elephant: {
EE: {
James: {}
}
}
}
Here is my fiddle:
https://jsfiddle.net/kzaiwo/y9m2h60t/8/
Note:
Please disregard the LASTRECORD part. I just added that to complete the key-value pair (for the last pair) in the above example. Thank you!
Thanks!
If you keep a reference to a prev value, which starts off as the original json object, you can then continuously update it and its children. When you're updating your object within the while loop you can update prev, and set it to the last child object that you create so that on the next iteration of your loop that particular child object will be updated to contain the new key-value pairs.
const map = {
AA: 'Acrobatic Artist',
BB: 'Baddest Banana',
CC: 'Curious Camper',
DD: 'Desperate Driver',
EE: 'Energetic Elephant'
};
const text = 'AA06ClaireCC04JackBB03TomEE05James';
function createJson(str) {
let json = {};
let prev = json;
let remainingText = str;
while (remainingText.length > 0) {
const tag = remainingText.substring(0, 2);
const len = remainingText.substring(2, 4);
const val = remainingText.substring(4, 4 + parseInt(len, 16));
const offset = tag.length + len.length + parseInt(len, 16);
remainingText = remainingText.substring(offset);
prev[map[tag]] = {};
prev[map[tag]][tag] = {};
prev = prev[map[tag]][tag][val] = {};
}
return json;
}
console.log(createJson(text));
Given the regular structure of your string (2-character code + 2-character number + characters), you can use a simple regex to split out the various parts.
From there you can (flat) map each section into an array of keys.
Finally, you can reduce-right the array to produce the result you want.
const map = {AA:"Acrobatic Artist",BB:"Baddest Banana",CC:"Curious Camper",DD:"Desperate Driver",EE:"Energetic Elephant"};
const text = "AA06ClaireCC04JackBB03TomEE05James";
// Parses a code, length and value from the start of the provided string
const parseSection = (str) => {
const [, code, valueLength] = str.match(/^(\w{2})([a-fA-F0-9]{2})/);
const length = parseInt(valueLength, 16) + 4;
return {
code,
length,
type: map[code],
value: str.slice(4, length),
};
};
// Iterates through the string, extracting sections until finished
const parseTlv = (str) => {
const sections = [];
while (str.length) {
const section = parseSection(str);
sections.push(section);
str = str.slice(section.length);
}
return sections;
};
// Map each section to a flat array of keys then reduce-right to form
// a tree structure
const lastRecord = {};
const result = parseTlv(text)
.flatMap(({ type, code, value }) => [type, code, value])
.reduceRight(
(obj, key) => ({
[key]: obj,
}),
lastRecord
);
console.log(result);
.as-console-wrapper { max-height: 100% !important; }
Here is a two part solution:
for() loop: create an array of items based on <tag><len><val> patterns
.reduce(): build the nested object from the items array
const input = 'AA06ClaireCC04JackBB03TomEE05James';
const tagMap = {
AA: 'Acrobatic Artist',
BB: 'Baddest Banana',
CC: 'Curious Camper',
DD: 'Desperate Driver',
EE: 'Energetic Elephant'
};
let items = [];
for(let i = 0; i < input.length; ) {
let tag = input.substring(i, i + 2);
let len = parseInt(input.substring(i + 2, i + 4), 16);
let val = input.substring(i + 4, i + 4 + len);
items.push([tag, val]);
i += 4 + len;
}
let result = {};
items.reduce((obj, arr) => {
const tag = arr[0];
const val = arr[1];
const name = tagMap[tag] || 'unknown';
//console.log(name, tag, val);
[name, tag, val].forEach(key => {
obj[key] = {};
obj = obj[key];
});
return obj;
}, result);
console.log(result);
Output:
{
"Acrobatic Artist": {
"AA": {
"Claire": {
"Curious Camper": {
"CC": {
"Jack": {
"Baddest Banana": {
"BB": {
"Tom": {
"Energetic Elephant": {
"EE": {
"James": {}
}
}
}
}
}
}
}
}
}
}
}
}
Note: the resulting object has an empty {} as the innermost value; you could replace that with "LASTRECORD" if needed

Create an Dynamic Array Object with key value pairs

I need to create an Dynamic key value pairs from the existing object
const balanceScheule = 1255;
const reqCost = [{Labour Cost: "1555"}, {Material Cost: "1575"}]; // key is dynamic and keeps on changing
const amfqtyCost = 1416;
Here the logic is to create an new array of object and subtract the amfqtyCost from reqCost
Logic i Have written
reqCost.forEach(element => {
const adjustedAmount = Object.entries(element).map((m) => {
let adjustedAmount = parseInt(m[1]) - amfqtyCost;
return adjustedAmount;
});
// console.log(...adjustedAmount)
});
this return 139 and 159 which is (1555 - 1416 = 139) and (1575 1416 = 159) respectively
Expected output :
[{Labour Cost: "139"}, {Material Cost: "159"}]
How to do i merge ?
You just need to return the updated object from within map function. Also for the outer iteration use map instead of forEach to return the final result
const balanceScheule = 1255;
const reqCost = [{
'Labour Cost': "1555",
}, {
'Material Cost': "1575",
}]; // key is dynamic and keeps on changing
const amfqtyCost = 1416;
const updatedData = reqCost.map(element => {
return Object.assign({}, ...Object.entries(element).map(([key, value]) => {
let adjustedAmount = parseInt(value) - amfqtyCost;
return {
[key]: String(adjustedAmount)
};
}));
});
console.log(updatedData);
You can do something like this:
const reqCost = [{
'Labour Cost': "1555"
}, {
'Material Cost': "1575"
}];
const amfqtyCost = 1416;
const adjustedCost = reqCost.map(cost => ({
[Object.keys(cost)[0]]: (parseInt(Object.values(cost)[0]) - amfqtyCost).toFixed(0)
}));
console.log(adjustedCost);
// OR, if you prefer to be a bit more verbose:
const adjustedCost2 = reqCost.map(cost => {
const [key, value] = Object.entries(cost)[0];
return {
[key]: (parseInt(value) - amfqtyCost).toFixed(0)
}
});
console.log(adjustedCost2);
You can reverse the Object.entries
{ key : value } => [ [ key, value ] ]
transformation by using Object.fromEntries
[ [ key, value ] ] => { key : value }
the code will look like this
reqCost.map((obj) =>
Object.fromEntries(
Object.entries(obj).map(([key, value]) => [
key,
parseInt(value) - amfqtyCost,
])
)
);

Process the Object and store in efficient way

I receive an Object (Object1) with basic pattern of Key and value, And then I want to process and save output in MongoDB, such that it contain Array objects for "Locations" and "Address" which are dynamic in nature.
Please suggest me any efficient way to do that.
const Object1 = {
date:'07-Sep-2020',
Address_1_Ftime: 2,
Address_1_Rtime: 0,
Address_1_Stime: 49,
Address_2_Ftime: 12,
Address_2_Rtime: 40,
Address_2_Stime: 9
Location1Name:'SAV2',Location1Val:30,
Location2Name:'LT232',Location2Val:130,
}
const Output =
{
date : '07-Sep-2020',
Address:
[
{
name:'Address_1',
Ftime:2,
Rtime:0,
Stime:49
},
{
name:'Address_2',
Ftime:12,
Rtime:40,
Stime:9
}
],
Locations:[
{
text:Location1,
name:SAV2,
value:30
},
{
text:Location1,
name:LT232,
value:130
}
]
}
After you finish your trying, please check the following code.
And let me know if you are not following something there.
const Object1 = {
date:'07-Sep-2020',
Address_1_Ftime: 2,
Address_1_Rtime: 0,
Address_1_Stime: 49,
Address_2_Ftime: 12,
Address_2_Rtime: 40,
Address_2_Stime: 9,
Location1Name:'SAV2',Location1Val:30,
Location2Name:'LT232',Location2Val:130,
};
// Initialize the output
const Output = {
Address: {},
Locations: {}
};
Object.keys(Object1).forEach(key => {
const value = Object1[key];
if (key === 'date') {
Output.date = value;
} else if (key.startsWith('Address')) {
const addressName = key.substr(0, key.length - 6);
const addressFieldKey = key.substr(key.length - 5);
Output.Address[addressName] = Output.Address[addressName] || {};
Output.Address[addressName][addressFieldKey] = value;
} else if (key.startsWith('Location')) {
const fieldKeyLength = key.endsWith('Name') ? 4 : 3;
const locationName = key.substr(0, key.length - fieldKeyLength);
const locationFieldKey = key.substr(key.length - fieldKeyLength);
Output.Locations[locationName] = Output.Locations[locationName] || {};
Output.Locations[locationName][locationFieldKey] = value;
}
});
// At this point, Address and Locations of Output are still objects not array. So you need the following change.
Output.Address = Object.keys(Output.Address).map(key => ({
name: key,
...Output.Address[key]
}));
Output.Locations = Object.keys(Output.Locations).map(key => ({
text: key,
name: Output.Locations[key].Name,
value: Output.Locations[key].Val
}));
console.log(Output);

decrease count value for array inside objects and count once reach zero automatically remove that object using java script

i have one object and its having service array i checked if any service id and offer id match with object its decrease count value and once count reach zero need to remove that object.please check my try in fiddle. i can able to reduce but while reaching zero not able to remove
const obj = {
name:'saloon',
services:[
{
sid:1,
offid:20,
count:2
},
{
sid:2,
offid:18,
count:1
},
{
sid:3,
offid:15,
count:3
}
]
}
given values : based on this service and offer id count should decrease once count reach zero need to remove that object
const servid = 2
const offid = 18
mycode
obj.services = obj.services.map(data => {
if(data.sid == servid && data.offid == offid ){
return data.count > 1 && {
sid:data.sid,
offide:data.offid,
count:data.count -1
}
}else{
return data
}
})
console.log(obj);
expected result :
const result = {
name:'saloon',
services:[
{
sid:1,
offid:20,
count:2
},
{
sid:3,
offid:15,
count:3
}
]
}
Use array#forEach to iterate through your array and check each sid and offid inside service, in case of match update the count value after that check if count value is less than or equal to zero, if it is, then using push its index into indexes array. After that, you can iterate through indexes array and delete those values in services array using array#splice.
const obj = { name:'saloon', services:[ { sid:1, offid:20, count:2 }, { sid:2, offid:18, count:1 }, { sid:3, offid:15, count:3 } ] };
const servid = 2;
const offid = 18;
var indexes = [];
obj.services.forEach(function(service, index) {
if(service.sid === servid && service.offid === offid){
--service.count;
}
if(service.count <= 0)
indexes.push(index);
});
indexes.reverse().forEach(function(index){
obj.services.splice(index, 1);
});
console.log(obj);
Use .forEach() to decrease the count, then .filter() to remove elements with count == 0:
const obj = {
name: 'saloon',
services: [{
sid: 1,
offid: 20,
count: 2
}, {
sid: 2,
offid: 18,
count: 1
}, {
sid: 3,
offid: 15,
count: 3
}]
}
const servid = 2
const offid = 18
obj.services.forEach((data, i) => {
if (data.sid == servid && data.offid == offid) {
data.count--;
}
})
obj.services = obj.services.filter(data => data.count > 0);
console.log(obj);

Removing object properties with Lodash

I have to remove unwanted object properties that do not match my model. How can I achieve it with Lodash?
My model is:
var model = {
fname: null,
lname: null
}
My controller output before sending to the server will be:
var credentials = {
fname: "xyz",
lname: "abc",
age: 23
}
I am aware I can use
delete credentials.age
but what if I have lots of unwanted properties? Can I achieve it with Lodash?
You can approach it from either an "allow list" or a "block list" way:
// Block list
// Remove the values you don't want
var result = _.omit(credentials, ['age']);
// Allow list
// Only allow certain values
var result = _.pick(credentials, ['fname', 'lname']);
If it's reusable business logic, you can partial it out as well:
// Partial out a "block list" version
var clean = _.partial(_.omit, _, ['age']);
// and later
var result = clean(credentials);
Note that Lodash 5 will drop support for omit
A similar approach can be achieved without Lodash:
const transform = (obj, predicate) => {
return Object.keys(obj).reduce((memo, key) => {
if(predicate(obj[key], key)) {
memo[key] = obj[key]
}
return memo
}, {})
}
const omit = (obj, items) => transform(obj, (value, key) => !items.includes(key))
const pick = (obj, items) => transform(obj, (value, key) => items.includes(key))
// Partials
// Lazy clean
const cleanL = (obj) => omit(obj, ['age'])
// Guarded clean
const cleanG = (obj) => pick(obj, ['fname', 'lname'])
// "App"
const credentials = {
fname:"xyz",
lname:"abc",
age:23
}
const omitted = omit(credentials, ['age'])
const picked = pick(credentials, ['age'])
const cleanedL = cleanL(credentials)
const cleanedG = cleanG(credentials)
Get a list of properties from model using _.keys(), and use _.pick() to extract the properties from credentials to a new object:
var model = {
fname:null,
lname:null
};
var credentials = {
fname:"xyz",
lname:"abc",
age:23
};
var result = _.pick(credentials, _.keys(model));
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.16.4/lodash.min.js"></script>
If you don't want to use Lodash, you can use Object.keys(), and Array.prototype.reduce():
var model = {
fname:null,
lname:null
};
var credentials = {
fname:"xyz",
lname:"abc",
age:23
};
var result = Object.keys(model).reduce(function(obj, key) {
obj[key] = credentials[key];
return obj;
}, {});
console.log(result);
You can easily do this using _.pick:
var model = {
fname: null,
lname: null
};
var credentials = {
fname: 'abc',
lname: 'xyz',
age: 2
};
var result = _.pick(credentials, _.keys(model));
console.log('result =', result);
<script src="https://cdn.jsdelivr.net/lodash/4.16.4/lodash.min.js"></script>
But you can simply use pure JavaScript (specially if you use ECMAScript 6), like this:
const model = {
fname: null,
lname: null
};
const credentials = {
fname: 'abc',
lname: 'xyz',
age: 2
};
const newModel = {};
Object.keys(model).forEach(key => newModel[key] = credentials[key]);
console.log('newModel =', newModel);
Lodash unset is suitable for removing a few unwanted keys.
const myObj = {
keyOne: "hello",
keyTwo: "world"
}
unset(myObj, "keyTwo");
console.log(myObj); /// myObj = { keyOne: "hello" }
Here I have used omit() for the respective 'key' which you want to remove... by using the Lodash library:
var credentials = [{
fname: "xyz",
lname: "abc",
age: 23
}]
let result = _.map(credentials, object => {
return _.omit(object, ['fname', 'lname'])
})
console.log('result', result)
You can use _.omit() for emitting the key from a JSON array if you have fewer objects:
_.forEach(data, (d) => {
_.omit(d, ['keyToEmit1', 'keyToEmit2'])
});
If you have more objects, you can use the reverse of it which is _.pick():
_.forEach(data, (d) => {
_.pick(d, ['keyToPick1', 'keyToPick2'])
});
To select (or remove) object properties that satisfy a given condition deeply, you can use something like this:
function pickByDeep(object, condition, arraysToo=false) {
return _.transform(object, (acc, val, key) => {
if (_.isPlainObject(val) || arraysToo && _.isArray(val)) {
acc[key] = pickByDeep(val, condition, arraysToo);
} else if (condition(val, key, object)) {
acc[key] = val;
}
});
}
https://codepen.io/aercolino/pen/MWgjyjm
This is my solution to deep remove empty properties with Lodash:
const compactDeep = obj => {
const emptyFields = [];
function calculateEmpty(prefix, source) {
_.each(source, (val, key) => {
if (_.isObject(val) && !_.isEmpty(val)) {
calculateEmpty(`${prefix}${key}.`, val);
} else if ((!_.isBoolean(val) && !_.isNumber(val) && !val) || (_.isObject(val) && _.isEmpty(val))) {
emptyFields.push(`${prefix}${key}`);
}
});
}
calculateEmpty('', obj);
return _.omit(obj, emptyFields);
};
For array of objects
model = _.filter(model, a => {
if (!a.age) { return a }
})
Recursively removing paths.
I just needed something similar, not removing just keys, but keys by with paths recursively.
Thought I'd share.
Simple readable example, no dependencies
/**
* Removes path from an object recursively.
* A full path to the key is not required.
* The original object is not modified.
*
* Example:
* const original = { a: { b: { c: 'value' } }, c: 'value' }
*
* omitPathRecursively(original, 'a') // outputs: { c: 'value' }
* omitPathRecursively(original, 'c') // outputs: { a: { b: {} } }
* omitPathRecursively(original, 'b.c') // { a: { b: {} }, c: 'value' }
*/
export const omitPathRecursively = (original, path, depth = 1) => {
const segments = path.split('.')
const final = depth === segments.length
return JSON.parse(
JSON.stringify(original, (key, value) => {
const match = key === segments[depth - 1]
if (!match) return value
if (!final) return omitPathRecursively(value, path, depth + 1)
return undefined
})
)
}
Working example: https://jsfiddle.net/webbertakken/60thvguc/1/
While looking for a solution that would work for both arrays and objects, I didn't find one and so I created it.
/**
* Recursively ignore keys from array or object
*/
const ignoreKeysRecursively = (obj, keys = []) => {
const keyIsToIgnore = (key) => {
return keys.map((a) => a.toLowerCase()).includes(key)
}
const serializeObject = (item) => {
return Object.fromEntries(
Object.entries(item)
.filter(([key, value]) => key && value)
.reduce((prev, curr, currIndex) => {
if (!keyIsToIgnore(curr[0]))
prev[currIndex] =
[
curr[0],
// serialize array
Array.isArray(curr[1])
? // eslint-disable-next-line
serializeArray(curr[1])
: // serialize object
!Array.isArray(curr[1]) && typeof curr[1] === 'object'
? serializeObject(curr[1])
: curr[1],
] || []
return prev
}, []),
)
}
const serializeArray = (item) => {
const serialized = []
for (const entry of item) {
if (typeof entry === 'string') serialized.push(entry)
if (typeof entry === 'object' && !Array.isArray(entry)) serialized.push(serializeObject(entry))
if (Array.isArray(entry)) serialized.push(serializeArray(entry))
}
return serialized
}
if (Array.isArray(obj)) return serializeArray(obj)
return serializeObject(obj)
}
// usage
const refObject = [{name: "Jessica", password: "ygd6g46"}]
// ignore password
const obj = ignoreKeysRecursively(refObject, ["password"])
// expects returned array to only have name attribute
console.log(obj)
let asdf = [{"asd": 12, "asdf": 123}, {"asd": 121, "asdf": 1231}, {"asd": 142, "asdf": 1243}]
asdf = _.map(asdf, function (row) {
return _.omit(row, ['asd'])
})

Categories

Resources