Convert array of objects to plain object using Ramda - javascript

How can I convert an array of objects to a plain object?
Where each item of the array is an object with only one key:value pair and the key have an unknown name.
I have this
const arrayOfObject = [
{KEY_A: 'asfas'},
{KEY_B: 'asas' }
]
let result = {}
const each = R.forEach((item) => {
const key = R.keys(item)[0]
result[key] = item[key]
})
return result
But I dislike that solution because the forEach is using a global variable result and I'm not sure how to avoid side effects here.

Ramda has a function built-in for this, mergeAll.
const arrayOfObject = [
{KEY_A: 'asfas'}
,{KEY_B: 'asas' }
];
R.mergeAll(arrayOfObject);
//=> {"KEY_A": "asfas", "KEY_B": "asas"}

Since everybody is using ES6 already (const), there is a nice pure ES6 solution:
const arrayOfObject = [
{KEY_A: 'asfas'},
{KEY_B: 'asas'}
];
Object.assign({}, ...arrayOfObject);
//=> {KEY_A: "asfas", KEY_B: "asas"}
Object.assing merges provided objects to the first one, ... is used to expand an array to the list of parameters.

Use reduce instead:
const arrayOfObject = [
{KEY_A: 'asfas'}
,{KEY_B: 'asas' }
];
const each = R.reduce((acc,value) => {
const key = R.keys(value)[0];
acc[key] = value[key];
return acc;
},{},arrayOfObject);
Since your array is an array of objects, you could also just call merge inside a reduce:
const each2 = R.reduce((acc,value) => R.merge(value,acc),{},arrayOfObject);
Here is a jsbin with both examples:
http://jsbin.com/mifohakeru/edit?js,console,output

Related

how can i check if an array of objects contains a key which is in array of strings js?

We have an array of objects like
const arr = [{id: "someId", name: {...}}, ...];
const skippedKeys = ["id"...]
How can i filtered the array of object based on skipped keys?
The result should be:
const result = [{name: {...}}, ...];
Also i don't want to make a cycle inside the cycle.
the result also could be implemented using lodash library.
we should remove key with value as well.
Since you stated that it could be implemented using lodash, here is some code using lodash:
let result = _.map(arr, (el)=> _.omit(el, skippedKeys))
const result = arr.map(obj =>
Object.keys(obj).reduce(
(res, key) => (
skippedKeys.includes(key) ? res : {...res, [key]: obj[key]}
),
{},
));
It's simple and no need for any nested cycles. There are two option to do that
Using includes function
const result = arr.filter((item) => !result.includes(item.id));
Using set
const dataSet = new Set(skippedKeys);
const result = arr.filter((item) => !dataSet.has(item.id));
I prefer the second one as it excludes double checks. Hope the answer was helpful.

Traversing Arrays by forEach

Trying to traverse an array into an object with key/pair (yes I know of reduce):
This is the array:
filtered2 = [["deviceName", "TestDevice00003"], ["hwModelName", "TestHwModel03"], ["deviceTypeName", "TestDeviceType03"], ["serviceTag", "A1A03"]]
But for some reason when I do forEach:
filtered2.forEach( (indiv) => {
console.log([indiv[0]]+" | " +[indiv[1]])
obj3 = {
...obj3,
[[indiv[0]][0]] : [indiv[1]]
}
})
Console.log will see each (indiv) as "hwModelName | TestHwModel03"
at [indiv[0]]+" | " +[indiv[1]], so both are basic strings
But the forEach function sees [indiv[1]] as Array ["TestHwModel03"]
So I have to go one more depth level [indiv[1]][0] into the array to get the unwrapped string "TestHwModel03"
Why there this difference?
Remove the square brackets surrounding the value.
filtered2 = [["deviceName", "TestDevice00003"], ["hwModelName", "TestHwModel03"], ["deviceTypeName", "TestDeviceType03"], ["serviceTag", "A1A03"]]
let obj3 = {}
filtered2.forEach( (indiv) => {
obj3 = {
...obj3,
[indiv[0]] : indiv[1]
}
})
console.log(obj3)
Although it's much simpler to use Object.fromEntries:
filtered2 = [["deviceName", "TestDevice00003"], ["hwModelName", "TestHwModel03"], ["deviceTypeName", "TestDeviceType03"], ["serviceTag", "A1A03"]]
let obj3 = Object.fromEntries(filtered2)
console.log(obj3)
You can use reduce method on an array to convert the array to a map. Or You can use Object.fromEntries if your env supports the latest version of ES2017.
filtered2 = [
["deviceName", "TestDevice00003"],
["hwModelName", "TestHwModel03"],
["deviceTypeName", "TestDeviceType03"],
["serviceTag", "A1A03"],
];
const toMap = (arr = []) =>
arr.reduce((acc, [key, value]) => {
acc[key] = value;
return acc;
}, {});
console.log(toMap(filtered2))
/// Other way
console.log(Object.fromEntries(filtered2))

Convert string array into object with same key/value

How do I convert ["one","two","three"] into {one:"one", two:"two", three:"three"}
import stringArray from './a.js';
class b {
hashmap = stringArray// convert this into Object here inline.
}
Before you jump I know of for how to achieve this in say constructor() with tricks like forEach, for in loop etc. Is there a simple one line code to achieve this in the class property not inside a function.
Lodash
You can use _.zipObject. It accepts two arrays - one for keys, another for values but if you just use the same array twice you'd get matching pairs:
const arr = ["one","two","three"];
const obj = _.zipObject(arr, arr);
console.log(obj);
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.15/lodash.min.js"></script>
Plain JavaScript
You can use Object.fromEntries to do the same thing. It works with an array of key-value pairs, so you'll have to transform yours to that:
const arr = ["one","two","three"];
const matchingKeyValuePairs = arr.map(x => [x, x]);
const obj = Object.fromEntries(matchingKeyValuePairs);
console.log(obj);
Also you can use Array#reduce to generate an object with a computed property name:
const arr = ["one","two","three"];
const obj = arr.reduce((acc, item) => ({...acc, [item]: item}), {});
console.log(obj);
data = ["one","two","three"];
data = data.map(e => [e,e]) // keyvalue pairs [["one","one"],["two","two"],["three","three"]]
data = Object.fromEntries(data); // {"one":"one","two":"two","three":"three"}
map will convert each element of your input array to a structure you want.
In this case, we want to convert each element to an array with the element repeated twice in it
Object.froEntries will convert a list of key-value pair to an Object
This can be also done with the plain old for loop
data = ["one","two","three"];
obj = {};
for(let i = 0; i < data.length ; i++){
obj[data[i]] = data[i];
}
Try this:
const arr = ["one","two","three"]
let obj = {}
arr.forEach(item => {obj[item] = item})
document.write(JSON.stringify(obj))
Lodash has the _.keyBy() function, that creates an object from an array by generating keys from the values via the function supplied (the iteratee). The default iteratee is _.identity(), which returns the value.
const arr = ["one","two","three"];
const obj = _.keyBy(arr);
console.log(obj);
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.15/lodash.min.js"></script>

convert nested array to nested obj in js

I am trying to convert the nested array to nested obj:
For ex,
let ip_array = [
["fdsfasdf","hghfhgh"],
["fsdf","hjghhjhj"],
["fdfss","hjghh"]
]
expected o/p :
let new_array = [
{"fsdfdsf":""fgdfgdfg},
{"dfdsd":"jhjghj"},
{"dfsddfds":"hghfh"}
]
This can be done with JavaScript's Array.map().
First, you use Array.map() to iterate through the input array, and return the result by using computed property names to set the key/property of each object.
const arr = [["fdsfasdf","hghfhgh"],["fsdf","hjghhjhj"],["fdfss","hjghh"]];
const res = arr.map(element => {
return {
[element[0]]: element[1]
};
});
console.log(res);
You could try
let ip_array = [["fdsfasdf","hghfhgh"],["fsdf","hjghhjhj"],["fdfss","hjghh"]]
let myObj = ip_array.map((a, k) => {
return { [a[0]]: a[1] };
})
An alternative approach using the newer Object.fromEntries() method.
Caution: This is very new method and is still in draft specification at the time of writing this answer in 2019. It may not be cross-browser compatible.
let ip_array = [
["fdsfasdf","hghfhgh"],
["fsdf","hjghhjhj"],
["fdfss","hjghh"]
]
let new_array = ip_array.map((arr)=> Object.fromEntries([arr]));
console.log(new_array);

Convert JSON to Array of Objects using lodash

I have a JSON object in NoSql database in this format. We are getting this data after migrating some records from some other database and these are multi-valued fields.(Basically we are trying to clean the data for further processing).
{
"BPContName":"aName;bName;cName",
"BPContEmail":"aEmail;bEmail;cEmail",
"BPContPWID":"aPWID;bPWID;cPWID"
}
I want to add another key "bpTableDataName" in the same JSON which should have this format and values,
"bpTableDataName": [
{
"name": "aName",
"email": "aEmail",
"pwdid": "aPWID"
},
{
"name": "bName",
"email": "bEmail",
"pwdid": "bPWID"
},
{
"name": "cName",
"email": "cEmail",
"pwdid": "cPWID"
}
],
Is there a way we can achieve this using lodash?
Try following code -
o = {
"BPContName": "aName;bName;cName",
"BPContEmail": "aEmail;bEmail;cEmail",
"BPContPWID": "aPWID;bPWID;cPWID"
}
map = { "BPContName" : "name", "BPContEmail": "email", "BPContPWID": "pwdid" }
const result = _.reduce(o, (arr, v, k) => ( v.split(";").forEach((x,i) => _.set(arr, `${i}.${map[k]}`, x)), arr ), [])
console.log(result)
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.11/lodash.min.js"></script>
You can use split() to split the values into an array.
Then iterate over the array and create the require json and then push that into results.
Check this out.
var data = {
"BPContName":"aName;bName;cName",
"BPContEmail":"aEmail;bEmail;cEmail",
"BPContPWID":"aPWID;bPWID;cPWID"
}
var names = data.BPContName.split(';');
var emails = data.BPContEmail.split(';');
var pwids = data.BPContPWID.split(';');
var results = [];
for(var i = 0 ; i < names.length; i++) {
var obj = {
name: names[i],
email: emails[i],
pwdid: pwids[i]
}
results.push(obj);
}
console.log(results)
You could reduce the entries returned by Object.entries like this:
let obj = {
"BPContName": "aName;bName;cName",
"BPContEmail": "aEmail;bEmail;cEmail",
"BPContPWID": "aPWID;bPWID;cPWID"
}
let bpTableDataName = Object.entries(obj).reduce((r, [key, value]) => {
let splits = value.split(";");
key = key.replace("BPCont", "").toLowerCase();
splits.forEach((split, i) => (r[i] = r[i] || {})[key] = split)
return r;
}, [])
obj.bpTableDataName = bpTableDataName;
console.log(obj)
Object.entries returns an array of key-value pair. Loop through each of them
split the each value at ;
get the key by removing BPCont part and making it lowerCase
Loop through the splits and update specific keys of objects at each index
Update:
Since you have an extra d in the output's key, you can create a mapping object:
propertyMap = {
"BPContName": "name",
"BPContEmail": "email",
"BPContPWID": "pwdid"
}
And inside the reduce, change the replace code to this:
key = propertyMap[key]
Using Object.assign, Object.entries, Array#map and the spread operator make this trivial
const inputdata = {
"BPContName":"aName;bName;cName",
"BPContEmail":"aEmail;bEmail;cEmail",
"BPContPWID":"aPWID;bPWID;cPWID"
};
const t1=Object.assign({},...Object.entries(inputdata).map(([k,v])=>({[k]:v.split(';')})));
inputdata.bpTableDataName=t1.BPContName.map((name,i)=>({name,email:t1.BPContEmail[i],pwdid:t1.BPContPWID[i]}));
console.log(inputdata);
Of course, it wouldn't be me without a one-liner
const obj = {
"BPContName":"aName;bName;cName",
"BPContEmail":"aEmail;bEmail;cEmail",
"BPContPWID":"aPWID;bPWID;cPWID"
};
// one line to rule them all
obj.bpTableDataName=Object.entries(obj).reduce((r,[k,v])=>(v.split(';').forEach((v,i)=>(r[i]=r[i]||{})[{BPContName:'name',BPContEmail:'email',BPContPWID:'pwdid'}[k]]=v),r),[]);
//
console.log(obj);
Basically what you need is to zip it.
Snippet:
let obj = {"BPContName":"aName;bName;cName","BPContEmail":"aEmail;bEmail;cEmail","BPContPWID":"aPWID;bPWID;cPWID"},
res = _.zipWith(
..._.map(obj, v => v.split(';')),
(name, email, pwid) => ({name, email, pwid})
);
console.log(res)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
Note, the sequence of the parameters we have to put such a way, the original object give us values when using Object.values or giving us keys when using Object.keys usually it is alphabetical order. But, In case in any env the order is not guranted we can sort it with a sequence of keys as a metadata.
Or else you can explicitly pass the arguments like:
(obj.BPContName.split(';'), obj.BPContEmail.split(';'), obj.BPContPWID.split(';'))
You can use lodash's _.flow() to create a function. Use _.map() with _.overArgs() to create a function that splits the values, format the key, and then converts them to an array of pairs using _.unzip(), for example [['name', 'x'], ['name', 'y']]. Transpose the array of arrays with _.unzip() to combine pairs of different properties. Then use _.map() to iterate, and convert each array of pairs to an object using _.fromPairs().
const { flow, partialRight: pr, map, unzip, overArgs, times, size, constant, split, fromPairs } = _
const keysMap = new Map([['BPContName', 'name'], ['BPContEmail', 'email'], ['BPContPWID', 'pwdid']])
const formatKey = key => keysMap.get(key)
const splitVals = pr(split, ';')
const fn = flow(
pr(map, overArgs(
(vals, k) => unzip([vals, times(size(vals), constant(k))]),
[splitVals, formatKey])
),
unzip, // transpose
pr(map, fromPairs) // convert each pairs array to object
)
const data = {
"BPContName":"aName;bName;cName",
"BPContEmail":"aEmail;bEmail;cEmail",
"BPContPWID":"aPWID;bPWID;cPWID"
}
const results = fn(data)
console.log(results)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>

Categories