Related
I'm working on a project where I get an object in input like this one :
const obj = {
a: 'somestring',
b: 42,
c: {
d: 'foo',
e: 'bar'
},
f: [1, 2]
};
and I need to create some variables to get to this output :
const a = "somestring"
const b = 42
const c.d = "foo"
const c.e = "bar"
const f[0] = 1
const f[1] = 2
I got a result with this code :
for (const [k1, v1] of Object.entries(obj)) {
if (typeof v1 === "object") {
if (Array.isArray(v1)) {
for (const [k2, v2] of Object.entries(v1)) {
console.log(`const ${k1}[${k2}] = ${v2}`);
}
} else {
for (const [k2, v2] of Object.entries(v1)) {
console.log(`const ${k1}.${k2} = ${v2}`);
}
}
} else {
console.log(`const ${k1} = ${v1}`);
}
}
But when I get an object more complex like this one :
const obj = {
a: [
{
b: 'lorem'
},
{
c: 'ipsum'
}
],
d: {
e: {
f : 'foobar'
}
}
};
My output look like this :
const a[0] = [object Object]
const a[1] = [object Object]
const d.e = [object Object]
I can't find any relevant solutions. Is there a solution or npm package for this?
There is a feature called destructuring docs click here
This feature as the docs say will help you create new variables from a nested object.
Taking a object which is nested you can access its leaf values and assign them directly to vars like this:
const o = {
a: 'a',
b: {
c : 'c',
d: {
e: 'e'
}
}
};
const {a ,b : { c, d: {e} }} = o;
alert(a);
alert(c);
alert(e);
Edit: it works with arrays as well not objects only
You can do it with eval function in JS:
const obj = {
a: 'somestring',
b: 42,
c: {
d: 'foo',
e: 'bar'
},
f: [1, 2]
};
var log = console.log;
for (let key in obj) {
//log(key);
eval(`var ${key} = obj.${key}`);
}
log(a);
log(b);
log(c);
log(f);
I think you want something like this:
const obj = {
a: 'somestring',
b: 42,
c: {
d: 'foo',
e: 'bar'
},
f: [1, 2]
};
const parse = (obj, prefix = '', isArray=false) => {
Object.entries(obj).forEach(([k, v]) => {
if (typeof v === 'object') parse(v, `${k}`, Array.isArray(v))
else {
const value = (typeof v === 'string') ? `"${v}"` : v;
const before = isArray ? '[' : prefix ? '.' : '';
const after = isArray ? ']' : '';
console.log(`const ${prefix}${before}${k}${after} = ${value}`)
}
});
}
parse(obj);
I'm parsing a csv fils to json with node-csvtojson and I got a JSONarray with the following code
csv({delimiter: ';'}).fromFile(path).then((jsonObj)=>{
data = jsonObj;
console.log(jsonObj);
})
with a csv like
a,b,c
A,B,C
1,2,3
1,B,C
I have got
[
{
a: A,
b: B,
c: C,
},
{
a: 1,
b: 2,
c: 3,
},
{
a: 1,
b: B,
c: C
}
]
But I want to find every object who has the element a === 1 and I want to have all the content of the object,
like this:
{
a: 1,
b: 2,
c: 3,
},
{
a: 1,
b: B,
c: C,
}
But I 'm struggling to do that, I have tried with array.filter but without success then I have tried to do this with array.map but I got lost on how to do.
Do you have any idea on or I could do that ?
Than you
Use Array.filter like so:
const data = [{
a: 'A',
b: 'B',
c: 'C',
},
{
a: 1,
b: 2,
c: 3,
},
{
a: 1,
b: 'B',
c: 'C'
}
];
console.log(data.filter(({ a }) => a == 1));
If you want this to work with old browsers, here's an ES5-compliant version:
var data = [{
a: 'A',
b: 'B',
c: 'C',
},
{
a: 1,
b: 2,
c: 3,
},
{
a: 1,
b: 'B',
c: 'C'
}
];
console.log(data.filter(function(obj) {
return obj.a == 1
}));
Simple use Array.filter to filter through the object array and select the one having property a === 1
var arr = [{"a":"A","b":"B","c":"C"},{"a":1,"b":2,"c":3},{"a":1,"b":"B","c":"C"}];
const filteredArr = arr.filter(obj => obj.a === 1);
console.log(filteredArr);
Using Array.reduce you can do the same thing:
var arr = [{"a":"A","b":"B","c":"C"},{"a":1,"b":2,"c":3},{"a":1,"b":"B","c":"C"}];
const redArr = arr.reduce((acc, obj) => {
return acc = obj.a === 1 ? acc.concat(obj) : acc;
}, []);
console.log(redArr);
Using Array.map for this problem is not the right approach, although it is possible:
var arr = [{"a":"A","b":"B","c":"C"},{"a":1,"b":2,"c":3},{"a":1,"b":"B","c":"C"}];
const mapArr = arr.map(obj => obj.a === 1 ? obj : undefined).filter(obj => obj); //hack to remove undefined elements
console.log(mapArr);
console.log([{
a: 'A',
b: 'B',
c: 'C',
},
{
a: 1,
b: 2,
c: 3,
},
{
a: 1,
b: 'B',
c: 'C'
}
].filter(o => o.a === 1))
Try this :
var arr = [{"a":"A","b":"B","c":"C"},{"a":1,"b":2,"c":3},{"a":1,"b":"B","c":"C"}];
var res = arr.filter(obj => obj.a === 1);
console.log(res);
i know there has many answer for unique array
but they can't handle with array of array
what i want is
source array
[
1,
0,
true,
undefined,
null,
false,
['a', 'b', 'c'],
['a', 'b', 'c'],
['a', 'c', 'b'],
{ a: { b: 2 } },
{ a: { b: 2 } },
{ a: { b: 3 } },
{ a: { b: undefined } },
{ a: { } },
{ a: { b: 3, c: undefined } },
]
the return
[
1,
0,
true,
undefined,
null,
false,
['a', 'b', 'c'],
['a', 'c', 'b'],
{ a: { b: 2 } },
{ a: { b: 3 } },
{ a: { b: undefined } },
{ a: { } },
{ a: { b: 3, c: undefined } },
]
arr-unique can handle object[], but can't handle array of array
Set can't too
fail code
console.log(array_unique(data));
console.log([...new Set(data)]);
console.log(data.filter(function (el, index, arr)
{
return index == arr.indexOf(el);
}));
===================
update
i create a module for this array-hyper-unique, but didn't use json stringify because it has a bug when valuse is regexp
One easy method would be to stringify the arrays and objects in order to identify duplicates:
const input = [
1,
true,
['a', 'b', 'c'],
['a', 'b', 'c'],
{ a: { b: 2 } },
{ a: { b: 2 } },
{ a: { b: 3 } },
{ a: { b: 3, c: undefined } },
];
const outputSet = new Set();
const stringifiedObjs = new Set();
input.forEach(item => {
if (typeof item !== 'object') outputSet.add(item);
else {
// replace undefineds with something, else they'll be ignored by JSON.stringify:
const stringified = JSON.stringify(
item,
(k, v) => v === undefined ? 'undefined-value' : v
);
if (!stringifiedObjs.has(stringified)) {
outputSet.add(item);
stringifiedObjs.add(stringified)
}
}
});
console.log([...outputSet]);
Try by converting elements to string using JSON.stringify and use indexOf to push these elements to another array,only if the another array does not contain this element. Then again use map & JSON.parse to convert string to the original format
var data = [
1,
true, ['a', 'b', 'c'],
['a', 'b', 'c'],
{
a: {
b: 2
}
},
{
a: {
b: 2
}
},
{
a: {
b: 3
}
},
]
// Create a new array of only string
// map will give new array and JSON.stringify will convert elements to string
var newData = data.map(function(item) {
return JSON.stringify(item)
})
//An empty array which will contain only unique values
var uniques = [];
// loop over the array of stirngs and check
//if that value is present in uniques array
//if not then push the element
newData.forEach(function(item) {
if (uniques.indexOf(item) === -1) {
uniques.push(item)
}
});
//Convert array of string to json
var parsedArr = uniques.map(function(item) {
return JSON.parse(item)
});
console.log(parsedArr)
The reason you method does not work, is because the first ['a', 'b', 'c'], and the second ['a', 'b', 'c'] are different objects, as are the first and second instances of { a: { b: 2 } }.
Because of this, even though you add them to Set, they will be considered non-equivalent to each other, and therefore, not be filtered for uniqueness.
It seems you want to get a unique array based on the absolute values in each object. One easy way to do this is to use the ES6 Map like so:
function uniq(arr) {
var uniqMap = new Map()
arr.forEach(element => {
uniqMap.set(JSON.stringify(element), element)
})
return [...uniqMap.values()]
}
You can then get the result you are looking for:
uniq(data)
//Result: [ 1, true, [ 'a', 'b', 'c' ], { a: { b: 2 } }, { a: { b: 3 } } ]
You could take a recursive approach for objects and check the values.
function check(a, b) {
if (!a || typeof a !== 'object') {
return a === b;
}
var keys = Object.keys(a);
return keys.length === Object.keys(b).length
&& keys.every(k => k in b && check(a[k], b[k]));
}
var array = [1, 0, true, undefined, null, false, ['a', 'b', 'c'], ['a', 'b', 'c'], ['a', 'c', 'b'], { a: { b: 2 } }, { a: { b: 2 } }, { a: { b: 3 } }, { a: { b: undefined } }, { a: {} }, { a: { b: 3, c: undefined } }],
unique = array.reduce((r, b) => (r.some(a => check(a, b)) || r.push(b), r), []);
console.log(unique);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Suppose I have an array of strings that represent keys such as ['a', 'b', 'd'], and an existing object such as...
const obj = {
a: 1,
b: 2,
c: 3,
d: 4,
e: 5
}
Is there a method of creating a new object that is a filtered version of obj based on the keys in the array such that...
const updated = {
a: 1,
b: 2,
d: 4
}
using the Object.assign() function?
I know it works with a function such as...
function createNew(o, keys) {
const updated = {}
Object.keys(o).forEach(k => {
if (keys.includes(k)) updated[k] = o[k]
})
return updated
}
but I'm looking for a solution with Object.assign()
const obj = {
a: 1,
b: 2,
c: 3,
d: 4,
e: 5
};
const desiredKeys = ['a', 'c', 'd'];
const result = desiredKeys.reduce((acc, key) => {
acc[key] = obj[key];
return acc;
}, {});
console.log(result);
What's an elegent way - purely functional, ideally - to transform (reduce?) this array:
var in = [
{ a: 1, b: 'x', c: 'foo' },
{ a: 1, b: 'y', c: 'goo' },
{ a: 2, b: 'x', c: 'hoo' },
{ a: 2, b: 'y', c: 'joo' }
]
Into this:
var out = [
{ a: 1, x: 'foo', y: 'goo' },
{ a: 2, x: 'hoo', y: 'joo' }
]
The logic is that all elements should be joined based on their a property, and all b and c properties denote key/value pairs respectively that should be merged into the single object based on their shared a value.
You can use a hash object, and reduce to wrap the hashing like this:
const arr = [
{ a: 1, b: 'x', c: 'foo' },
{ a: 1, b: 'y', c: 'goo' },
{ a: 2, b: 'x', c: 'hoo' },
{ a: 2, b: 'y', c: 'joo' }
];
let result = Object.values( // the result is the values of the hash object
arr.reduce((hash, o) => { // hash is a hash object that make it easier to group the result
hash[o.a] = hash[o.a] || {a: o.a}; // if there is no object in the hash that have the value of the key a equal to o.a, then create a new one
hash[o.a][o.b] = o.c; // set the value of the key stored in o.b to o.c
return hash;
}, {})
);
console.log(result);
You could use a closure with a Map
var input = [{ a: 1, b: 'x', c: 'foo' }, { a: 1, b: 'y', c: 'goo' }, { a: 2, b: 'x', c: 'hoo' }, { a: 2, b: 'y', c: 'joo' }],
output = input.reduce((map => (r, o) => (!map.has(o.a) && map.set(o.a, r[r.push({ a: o.a }) - 1]), map.get(o.a)[o.b] = o.c, r))(new Map), []);
console.log(output);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can use forEach and Object.assign to group by a and then map to return object values.
var data = [
{ a: 1, b: 'x', c: 'foo' },
{ a: 1, b: 'y', c: 'goo' },
{ a: 2, b: 'x', c: 'hoo' },
{ a: 2, b: 'y', c: 'joo' }
]
var r = {}
data.forEach(e => r[e.a] = Object.assign((r[e.a] || {}), {a: e.a, [e.b]: e.c}))
r = Object.keys(r).map(e => r[e])
console.log(r)
I like provided answers, but here is my attempt. I believe it's more readable, but it uses Object.assign and Object.values
const input = [
{ a: 1, b: 'x', c: 'foo' },
{ a: 1, b: 'y', c: 'goo' },
{ a: 2, b: 'x', c: 'hoo' },
{ a: 2, b: 'y', c: 'joo' }
]
const map = input.reduce((acc, obj) => {
const [a, key, value] = Object.values(obj)
const newObj = {a, [key]: value}
if (acc[a]) {
Object.assign(acc[a], newObj)
} else {
acc[a] = newObj
}
return acc
}, {})
console.log(Object.values(map))
Not sure if approach is elegant or functional, though returns expected result using for..of loops, Array.prototype.some() and Object.assign()
function props(array, key, prop1, prop2) {
let arr = [];
for (let obj of array) {
let o = {};
for (let {[key]:_key, [prop1]:_prop1, [prop2]:_prop2} of [obj]) {
o[_prop1] = _prop2;
o[key] = _key;
}
if (!arr.some(p => p[key] === o[key])) arr.push(o);
for (let prop of arr) {
if (prop[key] == o[key]) {
prop = Object.assign(prop, o)
}
}
}
return arr
}
var _in = [
{ a: 1, b: 'x', c: 'foo' },
{ a: 1, b: 'y', c: 'goo' },
{ a: 2, b: 'x', c: 'hoo' },
{ a: 2, b: 'y', c: 'joo' }
];
console.log(props(_in, "a", "b", "c"));