Traversing Arrays by forEach - javascript

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))

Related

Inserting Elements In Array As an Object but without using keys in Javascript

Current Situation :
[{
"Severity":1,
"Name":"Yash"
}, {
"Severity":2,
"Name":"Yashaswi"
}]
Desired Situation :
[{1: "Yash"}, {2: "Yashaswi"}]
Code being used :
widTags = ["Severity","Name"];
let tempobj = {};
for(let key in widTags) {
tempobj[key]=prop;
}
dataArrayWid.push(tempobj)
This solution does what you're suggesting without changing the syntax too much from your original code:
const original = [
{"Severity":1, "Name":"Yash"},
{"Severity":2, "Name":"Yashaswi"}
];
const final = [];
for (const oldObj of original){ // (Prefer `for...of` to iterate Arrays)
const
newObj = {},
key = oldObj["Severity"],
val = oldObj["Name"];
newObj[key] = val; // Uses Severity val as prop name & Name val as prop val
final.push(newObj);
}
console.log(final);
And this is a more concise version:
const
original = [ {"Severity":1, "Name":"Yash"}, {"Severity":2, "Name":"Yashaswi"} ],
final = original.map(obj => ( { [obj.Severity]: obj.Name } ));
console.log(final);
(Here, the .map method of Arrays makes a new Array with each element modified by a function -- in this case an Arrow function).
Note:
The extra parentheses tell JavaScript that their contents are an expression containing our Object literal to be returned, not a block of code statements.
Similarly, the extra brackets in the Object literal tell JavaScript that their contents are an expression specifying a computed property name, not a static property name,
You can achieve that by using Array.map() method.
Demo :
const dataArrayWid = [{
"Severity":1,
"Name":"Yash"
}, {
"Severity":2,
"Name":"Yashaswi"
}];
const result = dataArrayWid.map((obj) => {
return {
[obj.Severity]: obj.Name
}
});
console.log(result);

Create an array from an object with with key and its suffix

Looking for help to convert/group an object to an array using a key, the key has a difference with its (-)suffix.
const obj = {
"name-1":"a",
"age-1":"20",
"email-1":"a#email.com",
"name-2":"b",
"age-2":"24",
"email-2":"b#email.com",
"name-3":"c",
"age-3":"22",
"email-3":"c#email1.com"
};
Expected result
[
{
"name":"a",
"age":"20",
"email":"a#email.com"
},
{
"name":"b",
"age":"24",
"email":"b#email.com"
},
{
"name":"c",
"age":"22",
"email":"c#email.com"
}
]
Maybe due wrong search keyword unable to find a duplicate question.
You can run a reduce on Object.entries and split the keys say name-1, age-2 etc by '-' and return an array of objects.
const obj = {
"name-1":"a",
"age-1":"20",
"email-1":"a#email.com",
"name-2":"b",
"age-2":"24",
"email-2":"b#email.com",
"name-3":"c",
"age-3":"22",
"email-3":"c#email1.com"
};
const res = Object.entries(obj).reduce((acc, [key, value]) => {
const [ k, i ] = key.split('-');
acc[i - 1] = acc[i - 1] || {};
acc[i-1][k] = value;
return acc;
}, [])
console.log(res);
At the code above inside the reduce I split the key by '-' and it gives me a key of an object and the index of the final array.
Then I check if the index i - 1 exists in the array. If not then initialized it by an empty object. Here I use i - 1 because the given object keys are starting from 1 but an array starts from 0.
Finally, I put the object value into the newly created object.
This is a nice algorithm question that I will resolve by writing it with ES6 syntax.
You can achieve this thanks to some functions such as Object.entries and reduce
Example:
const obj = {
"name-1":"a",
"age-1":"20",
"email-1":"a#email.com",
"name-2":"b",
"age-2":"24",
"email-2":"b#email.com",
"name-3":"c",
"age-3":"22",
"email-3":"c#email1.com"
};
const result = Object.entries(obj)
// Here we destructure the entry with on the left the key, and value on the right
.reduce((accumulator, [key, value]) => {
const [property, index] = key.split('-');
// Get the value currently being filled, or an empty object if it doesn't
// exist yet.
const entry = accumulator[index] || {};
accumulator[index] = {
// Spread the current entry to which we are adding
// the property to the object being filled
...entry,
// Dynamic key syntax
[property]: value,
};
return accumulator;
}, [])
// Remove "holes" from the array since it's indexed with given keys
.filter(value => value !== undefined);
console.log(result);

how to get value if the object key is dynamic in typescript?

I have an array of object.structure is like that.
animal = [{"cow":{"leg":4,"eye":2}},{"monkey":{"leg":2,"eye":2}}]
here first key is dynamic like cow and monkey
so my question is how can i access the key leg if first key is dynamic
If you are sure that each object within the array has only 1 property (which would be the type of animal), you can do something like this.
animals = [{"cow":{"leg":4,"eye":2}},{"monkey":{"leg":2,"eye":2}}];
for (let animal of animals) {
let propName = Object.keys(animal)[0];
let result = animal[propName];
console.log(result); // <- Do what you want with it
}
You can use the newly added Object.entries, which make the most sense imo.
Thus for your data you have:
const animal = ...
for (a of animal) {
const [animalName, animalDesc] = Object.entries(a)[0]; // assumes there is only one
}
This will give you an array of objects with the contents of each animal.
animals.map(animal => animal[Object.keys(animal)[0]]);
1) Find an animal with that key
2) Return it with [animal]
3) Use it as you would (.leg)
const animals = [{ cow: { leg: 4, eye: 2 } }, { monkey: { leg: 2, eye: 2 } }];
const animal = 'cow';
const leg = animals.find(a => !!a[animal])[animal].leg;
Maybe convert it into a "non-dynamic-key" object?
const animal = [{"cow":{"leg":4,"eye":2}},{"monkey":{"leg":2,"eye":2}}]
const newanimal = animal.map(obj => {
const keys = Object.keys(obj)
return keys.map(key => ({ key, value: obj[key] }))
}).flat(Math.Infinity)
console.log(newanimal)
You can use map & Object.keys. map will return a new array. Object.keys is use to get all the keys inside each of the object in animal array.Then this line elem[getKeys].leg will retrieve the value of the leg key
let animal = [{
"cow": {
"leg": 4,
"eye": 2
}
}, {
"monkey": {
"leg": 2,
"eye": 2
}
}];
let legVal = animal.map((elem) => {
let getKeys = Object.keys(elem)[0];
return elem[getKeys].leg
})
console.log(legVal)

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>

Convert array of objects to plain object using Ramda

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

Categories