delete part of an object and place it in another object - javascript

I have an object (values). I want to select the field which startWith(')and which contains an object(for this case the 2). I want to delete the entire object from the createValue array and place it in an object CreateFileValue. You can check the output
Example input:
const values = {
ID: ,
c: [{
f: "",
v: 'hello',
},
{
f: "102",
fi: "doc.pdf",
v: {
f: 'F2',
fi: '',
v: 'jkhkjhkhkjh'
},
}
]
}
Example output:
const values = {
ID:817,
c: [{
f: "F",
v: 'hello',
}
],
c: {
"f": "F",
"fi": "ff.pdf",
"v": "jkhkjhkhkjh"
}
}
const values = {
ID: 7,
c: [{
f: "FL",
v: 'hello',
},
{
f: "F2",
fi: "doc.pdf",
v: {
f: '',
fi: '.pdf',
v: 'jkhkjhkhkjh'
},
}
]
}
const res = () => {
if (values.calues.startsWith('') && typeof values.cralues.startsWith('F') === 'object') {
return {
};
}
}
};
console.log(res());

const values = {
ID: 748817,
createValues: [{
field: "FLD_STR_101",
value: 'hello',
},
{
field: "FLD_STR_102",
fileName: "doc.pdf",
value: {
field: 'FLD_STR_102',
fileName: 'bulletin_paie_avril.pdf',
value: 'jkhkjhkhkjh'
},
}
]
}
// build createFileValues structure
values.createFileValues = values.createValues.filter(v => v.field.startsWith("FLD_STR_") && typeof v.value === "object");
// filter the files out of createValues
values.createValues = values.createValues.filter(v => !values.createFileValues.includes(v));
console.log(values);

values.createValues.startsWith('FLD_STR_') isn't valid because createValues is an array. You'll need to iterate over values.createValues in order to check each field.startsWith('FLD_STR_') and if value is an object (see How to detect if a variable is a pure javascript object for an example of this).
const values = {
ID: 748817,
createValues: [{
field: "FLD_STR_101",
value: 'hello',
},
{
field: "FLD_STR_102",
fileName: "doc.pdf",
value: {
field: 'FLD_STR_102',
fileName: 'bulletin_paie_avril.pdf',
value: 'jkhkjhkhkjh'
}
}
]
}
const res = () => {
var newResult = {
ID: values.ID,
createValues: []
};
values.createValues.forEach(function(item) {
var newCreateValue = {};
if (item.field.startsWith('FLD_STR_') && item.value.constructor.name === "Object") {
newCreateValue.field = item.value.field;
newCreateValue.value = item.value.value;
newCreateValue.fileName = item.value.fileName;
// if this is a createFilesValue, add it as a new key/value to the newResult object
newResult.createFileValues = newCreateValue;
} else {
newCreateValue.field = item.field;
newCreateValue.value = item.value;
// if this is an existing createValues, add it to the createValues array
newResult.createValues.push(newCreateValue);
}
});
return newResult;
};
console.log(res());

This should work
const values = {
ID: 748817,
createValues: [{
field: "FLD_STR_101",
value: 'hello',
},
{
field: "FLD_STR_102",
fileName: "doc.pdf",
value: {
field: 'FLD_STR_102',
fileName: 'bulletin_paie_avril.pdf',
value: 'jkhkjhkhkjh'
},
}
]
}
const res = (data) => {
let oldCreateValues = data.createValues;
let oldCreateFileValues = data.createFileValues;
let newCreateValues = [];
let newCreateFileValues = oldCreateFileValues && Array.isArray(oldCreateFileValues) ? oldCreateFileValues : [];
if (oldCreateValues && Array.isArray(oldCreateValues)) {
oldCreateValues.forEach(item => {
if (item.field.startsWith('FLD_STR_') && item.value && typeof item.value === 'object') {
newCreateFileValues.push(item);
} else {
newCreateValues.push(item);
}
});
}
data.createValues = newCreateValues;
data.createFileValues = newCreateFileValues;
return data;
};
console.log(res(values));

Related

Multiple Dynamic Filters in JavaScript Array

I can't seem to think about how I can overcome this issue where there might be any amount of filters as objects which will help me to filter out the data array.
data = [
{
id: 1,
first_name: 'Colver',
}, {
id: 2,
first_name: 'Brodie',
}, {
id: 3,
first_name: 'Philippa',
}, {
id: 4,
first_name: 'Taite',
}, {
id: 5,
first_name: 'Pierson'
}
];
filters = [
{
field: 'id',
operator: 'between',
value: '2-5'
},
{
field: 'first_name',
operator: 'eq',
value: 'Philippa'
}
];
ngOnInit(): void {
const filteredItems = [];
this.data.forEach(item => {
this.filters.forEach((filter, filterIndex) => {
const itemValue = item[filter.field];
switch (filter.operator) {
case 'eq':
if (itemValue === filter.value) {
filteredItems.push(item);
}
break;
case 'between':
const [firstValue, secondValue] = filter.value.split('-');
if (itemValue > firstValue && itemValue < secondValue) {
filteredItems.push(item);
}
break;
}
});
});
console.log(filteredItems);
}
I basically want the filteredItems to output like below since the id is between 2 and 5 and the first_name is Philippa. But since I'm iterating the filters 2 times both the times items gets pushed to filteredItems.
[{
id: 3,
first_name: 'Philippa',
}]
You could take Array#every and an object for getting the right operator function.
const
data = [{ id: 1, first_name: 'Colver' }, { id: 2, first_name: 'Brodie' }, { id: 3, first_name: 'Philippa' }, { id: 4, first_name: 'Taite' }, { id: 5, first_name: 'Pierson' }],
filters = [{ field: 'id', operator: 'between', value: '2-5' }, { field: 'first_name', operator: 'eq', value: 'Philippa' }],
operators = {
between: (field, range) => {
const [min, max] = range.split('-').map(Number);
return min <= field && field <= max;
},
eq: (field, value) => field === value
},
result = data.filter(o =>
filters.every(({ field, operator, value }) =>
operators[operator](o[field], value)
)
);
console.log(result);
You can perform a reduce operation over the filters array and use Array#filter to remove objects on each iteration.
const data = [
{
id: 1,
first_name: 'Colver',
}, {
id: 2,
first_name: 'Brodie',
}, {
id: 3,
first_name: 'Philippa',
}, {
id: 4,
first_name: 'Taite',
}, {
id: 5,
first_name: 'Pierson'
}
],
filters = [
{
field: 'id',
operator: 'between',
value: '2-5'
},
{
field: 'first_name',
operator: 'eq',
value: 'Philippa'
}
];
const res = filters.reduce((acc,{field,operator,value})=>
acc.filter(o => operator === 'eq' && o[field] === value ||
operator === 'between' && o[field] >= value.split('-')[0]
&& o[field] <= value.split('-')[1]), data);
console.log(res);
Use Array.prototype.every to make sure every filter passes, and if so, push it to the array:
ngOnInit(): void {
const filteredItems = this.data.forEach(item =>
this.filters.every((filter, filterIndex) => {
const itemValue = item[filter.field];
switch (filter.operator) {
case 'eq':
if (itemValue === filter.value) {
return true;
}
break;
case 'between':
const [firstValue, secondValue] = filter.value.split('-');
if (itemValue > firstValue && itemValue < secondValue) {
return true;
}
break;
}
return false;
})
);
console.log(filteredItems);
}
Instead of using
const filteredItems = [];
this.data.forEach(item => {
// [...]
filteresItems.push(item)
// [...]
});
use Array's filter:
const filteredItems = this.data.filter(item => {
// [...]
let match = true; // or false
return match;
});
Taking your whole example, you could use:
function passes(item, filter) {
const itemValue = item[filter.field];
switch (filter.operator) {
case 'eq':
if (itemValue === filter.value) {
return true;
}
case 'between':
const [firstValue, secondValue] = filter.value.split('-');
if (itemValue > firstValue && itemValue < secondValue) {
return true;
}
}
return false;
}
const filteredItems = this.data.filter(
item => this.filters
.map(filter => passes(item, filter))
.every());

Getting occurrences of different values on nested object

I've an array of objects like this:
arrObj = [{
id: 1
data: {
info: {
name: 'jhon'
}
}
},{
id: 1
data: {
info: {
name: 'jane'
}
}
},{
id: 1
data: {
info: {
name: 'jhon'
}
}
}]
And I needs get a summary of occurrences for different values, like this:
{ jane: 1, jhon: 2 }
The big problem is that I need pass the nested prop dynamically:
getSummary('data.info.name',obj) //--> { jane: 1, jhon: 2 }
Any ideas?
You can use the below code, this is just hint. you need to do error handling if some input is not having correct nested keys.
let arrObj = [{
id: 1,
data: {
info: {
name: 'jhon'
}
}
},{
id: 1,
data: {
info: {
name: 'jane'
}
}
},{
id: 1,
data: {
info: {
name: 'jhon'
}
}
}]
const getSummary = (dynamicKeys,obj) => {
const list = dynamicKeys.split('.');
const op = {};
for (let i = 0; i < obj.length; i++) {
let n = 1, key = obj[i][list[0]];
while (list.length > n) {
key = key[list[n]];
n++;
}
op[key] = op[key] ? op[key] + 1 : 1;
}
return op;
}
const test = getSummary('data.info.name', arrObj);
console.log(test)
A possible solution could be as below. Here at first given prop is found out from each element of arrayObj. If the finding isn't successful, the element is skipped and move to next. When the finding is successful, append the finding value to summary if it does not exist in summary or increment the existing value. You can change the code as your requirements.
const arrObj = [{
id: 1,
data: {
info: {
name: 'jhon'
}
}
}, {
id: 1,
data: {
info: {
name: 'jane'
}
}
}, {
id: 1,
data: {
info: {
name: 'jhon'
}
}
}];
const getSummary = (prop, arr) => {
const keys = prop.split('.');
const findPropValue = (elem) =>
keys.reduce((val, key, index) => {
if (index === 0) return elem[key];
return (val && val[key]) || val
}, null);
return arr.reduce((sum, curr) => {
const key = findPropValue(curr);
if (!key) return sum;
sum[key] = (sum[key] && sum[key] + 1) || 1;
return sum;
}, {});
};
console.log(getSummary('data.info.name', arrObj));
Go over elements using forEach. For each object, access the value and build a res object with keys as value (eg jane) and object values are aggregated.
[Access the value, by split the path, access object nested using reduce)
const getSummary = (path, items) => {
const paths = path.split(".");
const res = {};
items.forEach((item) => {
const value = paths.reduce((acc, cur) => acc[cur], item);
res[value] = (res[value] ?? 0) + 1;
});
return res;
};
arrObj = [
{
id: 1,
data: {
info: {
name: "jhon",
},
},
},
{
id: 1,
data: {
info: {
name: "jane",
},
},
},
{
id: 1,
data: {
info: {
name: "jhon",
},
},
},
];
const output = getSummary("data.info.name", arrObj);
console.log(output);

Can we assign an object key to another variable like this? [duplicate]

Given a JavaScript object, how can I convert it into an array of objects (each with key, value)?
Example:
var data = { firstName: 'John', lastName: 'Doe', email: 'john.doe#gmail.com' }
resulting like:
[
{ key: 'firstName', value: 'John' },
{ key: 'lastName', value: 'Doe' },
{ key: 'email', value: 'john.doe#gmail.com' }
]
var data = { firstName: 'John', lastName: 'Doe', email: 'john.doe#gmail.com' }
var output = Object.entries(data).map(([key, value]) => ({key,value}));
console.log(output);
Inspired By this post
Using map function
var data = { firstName: 'John', lastName: 'Doe', email: 'john.doe#gmail.com' };
var result = Object.keys(data).map(key => ({ key, value: data[key] }));
console.log(result);
You can just iterate over the object's properties and create a new object for each of them.
var data = { firstName: 'John', lastName: 'Doe', email: 'john.doe#gmail.com' };
var result = [];
for(var key in data)
{
if(data.hasOwnProperty(key))
{
result.push({
key: key,
value: data[key]
});
}
}
The previous answer lead me to think there is a better way...
Object.keys(data).map(function(key) {
return { key, value: data[key] };
});
or in ES6 using arrow functions:
Object.keys(data).map((key) => ({ key, value: data[key] }));
Just make your life easier and use es6 syntax with a map
var output = Object.keys(data).map(key => {
return {
key: key,
value: data[key]
};
})
var result = [];
for(var k in data) result.push({key:k,value:data[k]});
Or go wild and make the key and value keys customizable:
module.exports = function objectToKeyValueArray(obj, keyName = 'key', valueName = 'value') {
return Object
.keys(obj)
.filter(key => Object.hasOwnProperty.call(obj, key))
.map(key => {
const keyValue = {};
keyValue[keyName] = key;
keyValue[valueName] = obj[key];
return keyValue;
});
};
An alternative method for doing this that works on multi level objects and does not use recursion.
var output = []
var o = {
x:0,
y:1,
z:{
x0:{
x1:4,
y1:5,
z1:6
},
y0:2,
z0:[0,1,2],
}
}
var defer = [ [ o ,[ '_root_' ] ] ]
var _defer = []
while(defer.length){
var current = defer.pop()
var root = current[1]
current = current[0]
for(var key in current ){
var path = root.slice()
path.push(key)
switch( current[key].toString() ){
case '[object Object]':
_defer.push( [ current[key] , path ] )
break;;
default:
output.push({
path : path ,
value : current[key]
})
break;;
}
}
if(!defer.length)
defer = _defer.splice(0,_defer.length)
}
[
{ path: [ '_root_', 'x' ], value: 0 },
{ path: [ '_root_', 'y' ], value: 1 },
{ path: [ '_root_', 'z', 'y0' ], value: 2 },
{ path: [ '_root_', 'z', 'z0' ], value: [ 0, 1, 2 ] },
{ path: [ '_root_', 'z', 'x0', 'x1' ], value: 4 },
{ path: [ '_root_', 'z', 'x0', 'y1' ], value: 5 },
{ path: [ '_root_', 'z', 'x0', 'z1' ], value: 6 }
]
const array = [
{ key: "key1", value: "value1" },
{ key: "key2", value: "value2" },
];
const obj = Object.fromEntries(array.map(item => [item.key, item.value]));
console.log(obj);
I would say to use npm package flat.
works amazing for nested objects and arrays.
var flatten = require('flat')
flatten({
key1: {
keyA: 'valueI'
},
key2: {
keyB: 'valueII'
},
key3: { a: { b: { c: 2 } } }
})
// {
// 'key1.keyA': 'valueI',
// 'key2.keyB': 'valueII',
// 'key3.a.b.c': 2
// }
const array = [
{ key: "key1", value: "value1" },
{ key: "key2", value: "value2" },
];
const obj = Object.fromEntries(array.map(item => [item.key, item.value]));
console.log(obj);

summarize values of objects with same attribute name

I have an array filled with objects. The following example shows the structure of the objects.
let array = [
{
data: [{name:'a', value:20}, {name:'b', value:10}, {name:'c', value:5}]
},
{
data: [{name:'d', value:20}, {name:'a', value:10}, {name:'e', value:40}]
},
{
data: [{name:'b', value:30}, {name:'a', value:5}]
}
];
I'm trying to iterate through all the data values and summarize all the identical letters and sum up there values in a new array. So the new array should look like this:
let array = [{name:'a', value:35}, {name:'b', value:40}, {name:'c', value:5}, {name:'d', value:20}, {name:'e', value:40}];
This is my current approach but I don't get it to work.
let prevData = '';
let summarizedArray = [];
for(let i = 0; i < array.length; i++) {
for(let j = 0; j < array[i].data.length; j++) {
if(prevData === array[i].data[j].name) {
let summarized = {
name: array[i].data[j].name;
value: prevData.value + array[i].data[j].value;
}
summarizedArray.push(summarized);
}
prevData = array[i].data[j];
}
}
// Edited Example:
let array = [
{
data: [{name:'a', value1:20, value2:90, value3:'foo'},
{name:'b', value1:30, value2:20, value3:'boo'}]
},
data: [{name:'c', value1:5, value2:10, value3:'goo'},
{name:'a', value1:30, value2:20, value3:'foo'}]
},
{
];
The values should be bundled by same names. The values of Value1 and Value2 should be added up and Value3 is always the same for each name.
So the result should look like this:
let result = [{name:'a', value1:50, value2:110, value3:'foo'},
{name:'b', value1:30, value2:20, value3:'boo'},
{name:'c', value1:5, value2:10, value3:'goo'}
];
You could take a Map and collect all values. Later get an array of object of the collected values.
let array = [{ data: [{ name: 'a', value: 20 }, { name: 'b', value: 10 }, { name: 'c', value: 5 }] }, { data: [{ name: 'd', value: 20 }, { name: 'a', value: 10 }, { name: 'd', value: 40 }] }, { data: [{ name: 'b', value: 30 }, { name: 'a', value: 5 }] }],
result = Array.from(
array.reduce(
(m, { data }) => data.reduce(
(n, { name, value }) => n.set(name, (n.get(name) || 0) + value),
m
),
new Map
),
([name, value]) => ({ name, value })
);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
For a more convoluted object, you could take single properties to add, after a check for the type.
var array = [{ data: [{ name: 'a', value1: 20, value2: 90, value3: 'foo' }, { name: 'b', value1: 30, value2: 20, value3: 'boo' }] }, { data: [{ name: 'c', value1: 5, value2: 10, value3: 'goo' }, { name: 'a', value1: 30, value2: 20, value3: 'foo' }] }],
result = Array.from(
array.reduce(
(m, { data }) => {
data.forEach(o => {
var temp = m.get(o.name);
if (!temp) {
m.set(o.name, temp = {});
}
Object.entries(o).forEach(([k, v]) => {
if (k === 'name') return;
if (typeof v === 'number') {
temp[k] = (temp[k] || 0) + v;
} else {
temp[k] = v;
}
});
});
return m;
},
new Map
),
([name, value]) => Object.assign({ name }, value)
);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Find object by property key deep Javascript

I have the following code:
You can go to jsbin here..
https://jsbin.com/wupukuhita/1/edit?js,console
var foundObjects = [];
var findObjectByLabel = function(obj, key) {
var foundObject = [];
for(var i in obj) {
if(typeof obj[i] === "object"){
if(typeof obj[i][key] !== "undefined"){
foundObjects.push(obj[i]);
}
findObjectByLabel(obj[i],key);
}
}
return null;
};
I am iterating recursively over an object to find out if a certain property exists.
Then if it does exist, return the parent object.
You can check the jsbin link for a full example.
I do not like the foundObjects which is outside the function.
How can i put it inside the function and just return from the function the objects that contain a certain property.
https://jsbin.com/wupukuhita/1/edit?js,console
You can use javascript closures which is basically a function inside another function and the second function can access the main function objects
see the full code here , it works the same as your except we return the array
var foundObjects = function (obj,key) {
var foundObject = [];
var findObjectByLabel = function(obj,key) {
for (var i in obj) {
if (typeof obj[i] === 'object') {
if (typeof obj[i][key] !== 'undefined') {
foundObject.push(obj[i]);
}
findObjectByLabel(obj[i], key);
}
}
return null;
};
findObjectByLabel(obj,key);
return foundObject ;
}
var mainObj = {
name: 'MainForm', // main form
type: 'Form',
dirty: false,
valid: true,
Errors: [],
formOrInputElements: [
{
name: 'Age', // normal input
type: 'Text',
value: '',
dirty: true,
valid1: true,
test: {
name: 'test',
valid1: false,
},
Errors: [],
},
{
name: 'CNP', // normal input
type: 'Text',
value: '',
dirty: true,
valid: true,
Errors: [],
},
],
};
let foundObject = foundObjects(mainObj, 'valid1');
console.log(foundObject[0]);
console.log(foundObject[1]);
Alternatively, you can use array#reduce and iterate through each of the key values in object. In case of an array, recursively invoke the function
for each object. In case of an object, invoke the function with that object.
var mainObj = { name: "MainForm", type: "Form", dirty: false, valid: true, Errors: [], formOrInputElements: [ { name: "Age", type: "Text", value: "", dirty: true, valid1: true, test: { name: "test", valid1: false }, Errors: [] }, { name: "CNP", type:"Text", value: "", dirty: true, valid: true, Errors: [] } ] }
var findObjectByLabel = function(obj, key) {
return Object.keys(obj).reduce((r, k) => {
if (k === key) {
r.push(Object.assign({}, obj));
} else if (Array.isArray(obj[k])) {
obj[k].forEach(x => r = r.concat(findObjectByLabel(x, key)));
} else if (typeof obj[k] === 'object') {
r = r.concat(findObjectByLabel(obj[k], key));
}
return r;
}, []);
};
console.log(findObjectByLabel(mainObj, "valid1"));
.as-console-wrapper { max-height: 100% !important; top: 0; }
function findObjectByLabel(haystack, needle, buffer = []) {
if (typeof haystack === 'object') {
for (const prop in haystack) {
const result = prop === needle ? [haystack] : findObjectByLabel(haystack[prop], needle);
if (result.length > 0) {
buffer = buffer.concat(result);
}
}
}
return buffer;
}
// Unit test
function test_findObjectByLabel() {
const obj = {
foo: {
foo1: {
item1: 'item1',
item2: 'item2',
item3: 'item3',
},
foo2: {
item1: 'item1',
item2: 'item2',
item3: 'item3',
subFoo: {
item1: 'item1',
item2: 'item2',
needle: 'needle',
}
}
},
bar: {
bar1: {
item1: 'item1',
item2: 'item2',
item3: 'item3',
},
bar2: {
item1: 'item1',
item2: 'item2',
item3: 'item3',
needle: 'needle',
}
},
}
const expected = [
obj.foo.foo2.subFoo, // <-- contain "needle"
obj.bar.bar2, // <-- contain "needle"
];
const actual = findObjectByLabel(obj, 'needle');
if (JSON.stringify(actual) === JSON.stringify(expected)) {
console.log('Pass');
console.log('expected => ', JSON.stringify(expected, null, 4));
console.log('actual => ', JSON.stringify(actual, null, 4));
} else {
console.log('Fail');
console.log('Actual')
console.log(JSON.stringify(actual));
console.log('is not equal to expected');
console.log(JSON.stringify(expected));
}
}
test_findObjectByLabel();

Categories