Related
I have this set of data that I get dynamically -
This is the data I dynamically get
and my question is how can I get the values from the key, pattern and label and put them in a nested object like this - how should the nested object look like.
My current code is
let mergeTagsObj = {};
const merg = function(arr){
const propertyDataMap = arr.map(x => x.key);
propertyDataMap.forEach(x => {
mergeTagsObj[x] = {}
});
console.log(mergeTagsObj);
// console.log(object);
};
merg(displayArr)
displayArr has the data that I dynamically get, and I map each one to get the key so I can then give the object property a name. But after that I need to get the other 2 (pattern and label) and put it in the mergeTagsObj;
ex: mergeTagsObj = {
firstName:{
name:{label}
value:{pattern}
},
...
};
You can add the pattern and label in your forEach and any other logic that you might need to transform the data.
const data = [{key: 'firstName', pattern: "{{firstName}}", label: "First Name"},
{key: 'lastName', pattern: "{{lastName}}", label: "Last Name"},
{key: 'unsubscribeLink', pattern: "{{unsubscribeLink}}", label: "Unsubscribe Link"}
]
const transformDataToTagsObject = (dData) => {
const dynamicData = {};
dData.forEach((currentData, index) => {
const currentKey = currentData.key
const name = currentData.label
let value = currentData.pattern
if(currentData.key === 'unsubscribeLink'){
value = `<a href='${value}'>Unsubscribe</a>`
}
dynamicData[currentKey] = {
name,
value
}
})
const tagsObject = {
tags: dynamicData
}
return tagsObject;
}
const finalResults = transformDataToTagsObject(data)
console.log(finalResults)
Not most elegant solution, but I think this should work. Don't need to create the array of keys first you can just iterate over the arr of objects.
const merg = function(arr){
arr.forEach(x => {
mergeTagsObj[x.key] = {};
mergeTagsObj[x.key]['name'] = x.label;
mergeTagsObj[x.key]['value'] = x.pattern
});
console.log(mergeTagsObj);
// console.log(object);
};
// Given
const data = [
{key: "firstName", pattern: "{{firstName}}", label: "First Name"},
{key: "unsubscribeLink", pattern: "{{unsubscribeLink}}", label: "Unsubscribe Link"}
];
const tagsObject = data.reduce((obj, item) => {
const key = item.key;
const name = item.label;
let value = item.pattern;
if (key === 'unsubscribeLink') value = 'Unsubscribe';
return {...obj, [key]: {name, value}};
}, {});
console.log(tagsObject);
My array comes like this
var data=[{PRODUCT : P1}, {PRODUCT: P2}]
I wantt to convert this into [P1, P2].
Sometimes my array comes like this
var data=[{ITEM: I1, QUANTITY:1}, {ITEM: I2, QUANTITY:2}]
I wantt to convert this into [I1, I2].
so can we make a common function, where I just want to extract particular value of array and make a new array.
p.s. Thank you in advance
I tried to write the logic like this:
data.map((d, index) => { var result= [];
result.includes(d[0]); })
but it,s not dynamic
You could define a function which will always get the first value of the first object key, this should satisfy your needs based on the above
var data1 = [{
ITEM: 'I1',
QUANTITY: 1
}, {
ITEM: 'I2',
QUANTITY: 2
}]
var data2 = [{
PRODUCT: 'P1'
}, {
PRODUCT: ' P2'
}]
function getArrayOfValues(list) {
return list.reduce((acc, x) => {
const firstValue = Object.values(x)[0];
acc.push(firstValue)
return acc;
}, [])
}
const result1 = getArrayOfValues(data1)
console.log(result1)
const result2 = getArrayOfValues(data2)
console.log(result2)
function getProductOrItem(list) {
return list.reduce((accumulator, obj) => {
if (obj.PRODUCT) {
accumulator.push(obj.PRODUCT);
} else if (obj.ITEM) {
accumulator.push(obj.ITEM);
}
return accumulator;
}, [])
}
you can iterate through your array with map() method and inside it extract the value of a first entity of an object in your array and simply get a new array with all values:
const data1 =[{PRODUCT : 'P1'}, {PRODUCT: 'P2'}]
const data2 = [{ITEM: 'I1', QUANTITY: 1}, {ITEM: 'I2', QUANTITY: 2 }]
const transformValuesOfArray = (arrayToTransform) =>
arrayToTransform.map(value => {
const firstObjectValue = Object.values(value)[0]
return firstObjectValue
})
console.log(transformValuesOfArray(data1))
console.log(transformValuesOfArray(data2))
I have a list of objects:
[{name: 'Elza'}, {name: 'Tom'}, {name: 'Elza'}]
I use the below methods to get duplicated objects(by name) and assign a prop isDuplicated:
const duplicatedNames = arrayOfObjects
.map(e => e['name'])
.map((e, i, final) => final.indexOf(e) !== i && i++)
.filter(obj => arrayOfObjects[obj])
.map(e => !arrayOfObjects[e]['name']);
const result = arrayOfObjects.filter((obj, i) => {
return duplicatedNames.includes(obj.name) && Object.assign(obj, { isDuplicated: true });
});
I receive an array like:
[{name: 'Elza', isDuplicated: true}, {name: 'Tom'}, {name: 'Elza', isDuplicated: true}]
I would like to mark only the second occurrence of duplicate- so i would like the result to be:
[{name: 'Elza'}, {name: 'Tom'}, {name: 'Elza', isDuplicated: true}]
Can anyone know how to do it base on my code?
Here is a function that checks if a name exist more then once.
let data = [{name:'Elza'}, {name:'Tom'}, {name:'Elza'}, {name: "Jerry"}, {name: "Jerry"}];
function checkDup(arr){
let cache = [];
return arr.map(({name}, index) => {
if(!cache.find(el => el.name == name)){
cache.push({name, index});
return {name, index};
}
let { index: cacheIndex } = cache.find(el => el.name === name);
return {name,index: cacheIndex , isDuplicated: true};
})
}
console.log(checkDup(data));
You could create a Set of names. If the size of the set is same as after the name has been added, then it's duplicate record.
const input = [{name:'Elza'}, {name:'Tom'}, {name:'Elza'}],
names = new Set;
for (const o of input)
if (names.size === names.add(o.name).size)
o.isDuplicate = true
console.log(input)
You can try this:
let users = [{name:'Elza'}, {name:'Tom'}, {name:'Elza'}]
let flags = [], output = [];
users.forEach(user => {
if (flags[user.name]) {
output.forEach(item => {
if (item.name === user.name) {
item.isDuplicated = true
output.push(user);
}
})
} else {
flags[user.name] = true;
output.push(user);
}
})
Given your original array A, you could create a temporary array B and, for each a element of A, check:
if B contains a.name, then set a.isDuplicated to true;
else, push a.name in B.
let A = [{name: 'Elza'}, {name: 'Tom'}, {name: 'Elza'}];
let B = [];
A.forEach(a => {
if (B.includes(a.name)) {
a.isDuplicated = true;
} else {
B.push(a.name);
}
});
console.log(A);
You can use reduce with a helper object:
const collection = [{ name: 'Elza'}, { name: 'Tom'}, { name: 'Elza' }]
const helper = {}
const result = collection.reduce((acc, { name }) => {
if (helper[name]) {
return [...acc, { name, isDuplicate: true }]
}
helper[name] = 'x';
return [...acc, { name }]
}, [])
console.log(result)
I have created a function as shown below, which should append the array value into the first object.
Let's say we have given data below:
subjects = {
student1: ['Math', 'Science'],
student2: ['Math', 'Physics', 'English'],
};
students = {
student1: {
// other data
subjectsList: [],
},
student2: {
// other data
subjectsList: [],
},
};
Function code below:
const merge = (subjects: Object, students: Object) => {
Object.keys(subjects).forEach((id: Object) => {
const subjectsList = subjects[id];
const student = students[id];
if (student) {
const updatedStudent = {
...student,
subjectsList,
};
students[id] = updatedStudent;
}
});
return students;
};
This would result in a flow error:
Cannot access the computed property using object type [1].
app/reducers/subjects.reducer.js:42:32
42| const student = students[id];
^^
References:
app/reducers/subjects.reducer.js:40:48
40| Object.keys(subjects).forEach((id: Object) => {
^^^^^^ [1]
Object.keys(subjects).forEach((id: Object)
The id in the .forEach((id) => is not an Object, but a String
If you remove the typehinting (or whatever it is called).
const merge = (subjects, students) => {
Object.keys(subjects).forEach((id) => {
const subjectsList = subjects[id];
const student = students[id];
if (stand) {
const updatedStudent = {
...student,
subjectsList,
};
students[id] = updatedStudent;
}
});
return students;
};
I think this will work.
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'])
})