Javascript unwanted "empty" property after merging objects - javascript

I want to merge objects based on a property, and I want to use this property as the key for the merged array.
here is my code:
let mergedProfiles = [];
for (let set of profiles) {
if (Object.keys(mergedProfiles).indexOf(String(set.profile_id)) >= 0) { // if profile id exists
mergedProfiles[set.profile_id].push(set);
} else {
mergedProfiles[set.profile_id] = [];
mergedProfiles[set.profile_id].push(set);
}
}
example of profile object: {user_id: 17, name: "test", country: "US", bid: 0.02, profile_id: "1", user_id: 12}
the merge is working fine but for some reason I cant understand I always end up with empty as my first property in the mergedProfiles, any idea what am Imissing?

You could take an object instead of an array, because you get a sparse array with not used indices.
var profiles = [{ user_id: 17, name: "test", country: "US", bid: 0.02, profile_id: "1", user_id: 12 }],
mergedProfiles = {},
s;
for (s of profiles) {
if (!mergedProfiles[s.profile_id]) {
mergedProfiles[s.profile_id] = [];
}
mergedProfiles[s.profile_id].push(s);
}
console.log(mergedProfiles);
.as-console-wrapper { max-height: 100% !important; top: 0; }

You will want to store the results in an object so you can reference by key.
const allProfiles = {};
for(let set of profiles) {
if(typeof allProfiles[set.profile_id] === "undefined") {
allProfiles[set.profile_id] = [set];
}
else {
allProfiles[set.profile_id].push(set);
}
}
The reason your first element is empty is that you are declaring an empty JavaScript array and then failing to initialize all of the elements.
If you do something like
var someArray = [];
someArray[5] = 10;
console.log(someArray); // [empty × 5, 5]
then the result is a sparse array where the first 5 elements (0 - 4) are all empty or in other words undefined. In your example you are doing the same as above where your profile_id is some integer greater than 0.

Related

Insert all properties from an object within an array to another object in array using JS/TS

I have been looking a simple way to copy/insert/move properties in an object within an array to another object. I came up with a basic logic which does the job perfectly but am not satisfied with this. There has to be a better way, any help here?
var first = [
{
"AGREE_EFF_DATE__0": "02-Aug-2018",
"AGREE_TERM_DATE__0": "30-Apr-2021",
"AGREE_IND__0": "P1",
"P_DBAR_IND__0": "N",
"AGREE_EFF_DATE__1": "01-May-2021",
"AGREE_TERM_DATE__1": null,
"AGREE_IND__1": "NP",
"P_DBAR_IND__1": "N",
"PROVIDER_SPECIALITY__0": "PSYCHOLOGY, CLINICAL",
"PROVIDER_SPECIALITY_CODE__0": "CK"
}
];
var second = [
{
"STATUS": "ACTIVE",
"MEDICARE_NUMBER" : 12345
}
];
for(let i = 0; i < second.length; i++) {
var first_keys = Object.keys(first[i]);
var first_values = Object.values(first[i]);
for(let j = 0; j < first_keys.length; j++) {
second[i][first_keys[j]] = first_values[j];
}
}
console.log(second);
//Output-
[
{
STATUS: 'ACTIVE',
MEDICARE_NUMBER: 12345,
AGREE_EFF_DATE__0: '02-Aug-2018',
AGREE_TERM_DATE__0: '30-Apr-2021',
AGREE_IND__0: 'P1',
P_DBAR_IND__0: 'N',
AGREE_EFF_DATE__1: '01-May-2021',
AGREE_TERM_DATE__1: null,
AGREE_IND__1: 'NP',
P_DBAR_IND__1: 'N',
PROVIDER_SPECIALITY__0: 'PSYCHOLOGY, CLINICAL',
PROVIDER_SPECIALITY_CODE__0: 'CK'
}
]
When possible, you should prefer iteration to manually indexed loops. This means arr.map() or arr.forEach() or arr.reduce(), to name a few.
Also, You can use an object spread to easily merge objects together.
Putting those together, you can reduce this logic to:
const result = first.map((firstObj, i) => ({ ...firstObj, ...second[i] }))
Here we map() over all members of first, which returns a new array where each member is the result of the function. This function takes the array member as the first argument, and the index of that member as the second argument. Then we can use that index to find the corresponding item in the second array.
Then you just spread both objects into a new object to assemble the final result.
var first = [
{ a: 1, b: 2 },
{ a: 4, b: 5 },
];
var second = [
{ c: 3 },
{ c: 6 },
];
const result = first.map((firstObj, i) => ({ ...firstObj, ...second[i] }))
console.log(result)
Which is all perfectly valid typescript as well.
NOTE: there is one difference between my code any yours. Your code modifies the objects in second. My code returns new objects and does not change the contents of second at all.
This is usually the better choice, but it depends on how you use this value and how data is expected to flow around your program.
You need to be careful with iterating, because you can have different count of elements in first and second arrays. So the possible solution will be like this:
const first = [
{
"AGREE_EFF_DATE__0": "02-Aug-2018",
"AGREE_TERM_DATE__0": "30-Apr-2021",
"AGREE_IND__0": "P1",
"P_DBAR_IND__0": "N",
"AGREE_EFF_DATE__1": "01-May-2021",
"AGREE_TERM_DATE__1": null,
"AGREE_IND__1": "NP",
"P_DBAR_IND__1": "N",
"PROVIDER_SPECIALITY__0": "PSYCHOLOGY, CLINICAL",
"PROVIDER_SPECIALITY_CODE__0": "CK"
}
];
const second = [
{
"STATUS": "ACTIVE",
"MEDICARE_NUMBER": 12345
}
];
console.log(mergeAll(first, second));
function mergeAll(firstArray, secondArray) {
const result = [];
const minLength = firstArray.length < secondArray.length ? firstArray.length : secondArray.length;
for (let i = 0; i < minLength; i++) {
result.push({...firstArray[i], ...secondArray[i]});
}
return result;
}

check array of objects and compare its object values

I have a simple array of objects and I'd like to check if all the object in that array has the same value for a specific property.
const arr = [{
name: "Test",
value: 90
}, {
name: "OP",
value: 90
}, {
name: "Test",
value: 120
}]
Here I want to compare all the value property of every object element.
// get first objects value for comparison
let same_value = arr[0]['value'];
for(let i = 0; i < arr.length; i ++) {
if (arr[i]['value'] != same_value) {
return false;
}
}

adding another key and value to an object inside an array with JS

So I currently have a bunch of objects inside an array like below. However, I'm now trying to write a function that allows me to add another key|value into the object that was added last.
My current idea is using the arrayname.length - 1 to work out the position of the object within the array.
Would I need to create a temporary array to store the new object and then set (tempArray = oldArray) at the end of the function or would I concatinate them both?
const state = [
{
userId: 1,
},
{
Name: name,
},
{
age: 52,
},
{
title: "et porro tempora",
}]
this is the current code
let objects = [];
const addParent = (ev) =>{
ev.preventDefault();
// getting the length of the objects array
let arrayLength = objects.length;
// if the length of the array is zero - empty or one then set it to default zero
// else if there is objects stored in the array minus 1 to get the array position
if(arrayLength <= 0){
arrayLength = 0;
}else{
arrayLength = objects.length - 1;
}
//make a temporary array to be able to push new parent into an existing object
var tempObjects = []
for (var index=0; index<objects.length; index++){
}
//create a new parent object key : value
let parent = {
key: document.getElementById('key').value,
value: document.getElementById('value').value
}
//push parent object key and value into object
//objects.push(parent);
}
document.addEventListener('DOMContentLoaded', () => {
document.getElementById('btn1').addEventListener('click', addParent);
});
There are multiple ways to do this.
Try this one
var objects = [{
name: "1"
}];
const addParent = (ev) => {
let parent = {
key: "some value",
value: "some value"
}
objects = Array.isArray(objects) ? objects : [];
let lastObjectIndex = objects.length - 1;
lastObjectIndex = lastObjectIndex > -1 ? lastObjectIndex : 0
objects[lastObjectIndex] = { ...objects[lastObjectIndex],
...parent
}
}
I think You want to add new value to last object of the array
Method 1
const state = [
{
userId: 1,
},
{
Name: name,
},
{
age: 52,
},
{
title: "et porro tempora",
}]
state[state.length - 1].newKey = "value"
console.log(state)
Method 2
const state = [
{
userId: 1,
},
{
Name: name,
},
{
age: 52,
},
{
title: "et porro tempora",
}]
// 1st method
state[state.length - 1] = {
...state[state.length - 1] ,
newKey : "value"
}
console.log(state)
You can probably use something like this:
const a = [
{ "a" : "a" },
{ "b" : "b" }
]
const c = a.map((obj, index) => {
if (index === a.length -1) {
return { ...obj, newProp: "newProp" }
}
return obj;
});
console.log(c)
This will add property on the last object using spread operator, you can look it up if you are new to JS but basically it will retain all the existing property and add the newProp to the object

Javascript - Create and populate associative array containing sub arrays

I'm trying to collate some data. I would like to populate an array containing sub arrays, for example, I have some json data that I am iterating over:
{
"name": "name1",
"prices": "209.67"
},
{
"name": "name1",
"prices": "350"
},
{
"name": "name2",
"price": "195.97"
},
I would like to create an array that ends up looking something like the following:
myArray['name1']prices[0] = 209.67,
prices[1] = 350,
['name2']prices[0] = 195.97
I thought that the code below would achieve what I wanted but it doesn't work. It throws an exception. It doesn't seem to recognise the fact that the prices are an array for a given index into the main array. Instead the prices appear at the same level as the names. I want the main array for a given name to contain an inner array of prices.. Does anybody have any idea how I could modify to make this work?
function doStuff() {
var cryptoData = getData();
var datasetValues = {};
datasetValues.names = [];
datasetValues.names.prices = [];
for (var result = 0; result < cryptoData.length; result++) {
var data = cryptoData[result];
if (datasetValues.names.indexOf(data.cryptoname) === -1)
{
datasetValues.names.push(data.cryptoname);
}
// This works
//datasetValues.names.prices.push(data.prices);
// This doesn't!
datasetValues.cryptoNames[data.cryptoname].prices.push(data.prices);
}
}
You could reduce the array by using an object and take a default object if the property is not set. Then push the price.
var data = [{ name: "name1", price: "209.67" }, { name: "name1", price: "350" }, { name: "name2", price: "195.97" }],
result = data.reduce((r, { name, price }) => {
r[name] = r[name] || { name, prices: [] };
r[name].prices.push(+price);
return r;
}, Object.create(null));
console.log(result);
Try this
function parseData(input){
return input.reduce(function(o,i){
o[i.name] = {};
if(!o[i.name]['prices']){
o[i.name]['prices'] = [];
}
o[i.name]['prices'].push(i.prices);
return o;
},{});
}

How can I delete a key in a nested Javascript object with a dynamic number of properties and without eval?

I am looking to delete a specific key from a nested Javascript object based on a list of dynamic properties. Here is an example of what I mean:
This is a sample object:
employees: [
{
name: "John",
id: 1234567890,
salary: 60000
},
{
name: "Jack",
id: 0987654321,
salary: 55000
}
],
location: {
building: {
address: "111 Main St"
}
}
I am looking to delete the address key when I am provided an array of ['location', 'building', 'address']
When I say "dynamic" I mean that I could also be provided with an array of ['employees', 1] so I cannot rely on a set number of nested properties.
The only approach that works for me right now is to use the dreaded eval, which is not a permanent solution since the Javascript objects that I am reading are written by users.
let jsObject = ... // the object shown above
let properties = ['location', 'building', 'address']
let evalString = ''
for (let i = 0; i < properties.length; i++){
evalString += '[\''+properties[i]+'\']'
}
eval('delete jsObject'+evalString)
What is an alternative to eval that will accomplish this same goal?
You could reduce the object by the keys and save the last key for deleting the object with that key.
function deleteKey(object, keys) {
var last = keys.pop();
delete keys.reduce((o, k) => o[k], object)[last];
return object;
}
var object = { employees: [{ name: "John", id: '1234567890', salary: 60000 }, { name: "Jack", id: '0987654321', salary: 55000 }], location: { building: { address: "111 Main St" } } };
console.log(deleteKey(object, ['location', 'building', 'address']));
.as-console-wrapper { max-height: 100% !important; top: 0; }
This method accepts an object and an array of properties, and removes the inner most property as required
function remove(obj, props) {
delete props.slice(0, -1).reduce((init, curr) => init && init[curr], obj)[[...props].pop()];
}
You can break your array into everything except the last element, get a reference to that and the call delete on the object using the last element. You can use reduce to easily build the object reference. You need to be careful with arrays because you can't use delete without leaving an empty slot — delete doesn't change the length.
Here's the basic idea:
function deleteProp(obj, keys){
let prop = keys.pop() // get last key
let c = keys.reduce((a, c) => a[c], obj) // get penultimate obj
if (Array.isArray(c)) c.splice(prop, 1) // if it's an array, slice
else delete c[prop] // otherwise delete
}
// Delete address
let obj = {employees: [{name: "John",id: 1234567890,salary: 60000},{name: "Jack",id: 0987654321,salary: 55000}],location: {building: {address: "111 Main St"}}}
deleteProp(obj, ['location', 'building', 'address'])
console.log(obj)
//Delete employee 1
obj = {employees: [{name: "John",id: 1234567890,salary: 60000},{name: "Jack",id: 0987654321,salary: 55000}],location: {building: {address: "111 Main St"}}}
deleteProp(obj, ['employees', 1])
console.log(obj)
//Delete employee 1 id
obj = {employees: [{name: "John",id: 1234567890,salary: 60000},{name: "Jack",id: 0987654321,salary: 55000}],location: {building: {address: "111 Main St"}}}
deleteProp(obj, ['employees', 1, 'id'])
console.log(obj)
Here is a sample that i'm sure could be trimmed down a bit but it explains each step and you should be able to see whats happening in it:
let jsObject = {
employees: [{
name: "John",
id: 1234567890,
salary: 60000
},
{
name: "Jack",
id: 0987654321,
salary: 55000
}
],
location: {
building: {
address: "111 Main St"
}
}
};
let properties = ['location', 'building', 'address'];
// we use this to traverse the object storing the parent
let parent = null;
// run over each property in the array
for (let i = 0; i < properties.length; i++) {
// check if this is the last property and we have the parent object
if (i + 1 == properties.length && parent)
delete parent[properties[i]]; // just delete the property from the object
else if (parent === null)
parent = jsObject[properties[i]] // set the initial parent
else
parent = parent[properties[i]] // set the parent to the property in the existing object
}
// log the output
console.log(jsObject);
You are going to want to throw error handling and checks to make sure you don't end up outside the object as well.
Navigate to the object that contains the property you want to delete, then delete it:
let jsObject = {
employees: [
{
name: "John",
id: 1234567890,
salary: 60000
},
{
name: "Jack",
id: 0987654321,
salary: 55000
}
],
location: {
building: {
address: "111 Main St"
}
}
};
let properties = ['location', 'building', 'address'];
let innerMost = jsObject;
for (let i = 0; i < properties.length - 1; i++) {
if (typeof innerMost !== "object" || innerMost === null) {
innerMost = null;
break;
}
innerMost = innerMost[properties[i]];
};
if (
innerMost !== null &&
typeof innerMost === "object" &&
properties.length > 0 &&
innerMost.hasOwnProperty(properties[properties.length - 1])
) {
delete innerMost[properties[properties.length - 1]];
console.log(jsObject);
} else console.log("Invalid path");

Categories

Resources