JavaScript manage object properties with duplicate property names - javascript

I have a JavaScript object:
var list = {
ListId: '',
Items: {}
};
What I want to do is to be able to add dynamic properties to Items property object. User can define properties with the same name but the logic should check if the property exists and if yes create same property name by adding a suffix or prefix (generated) but user will still see same property name.
Example:
var list = {
ListId: '',
Items: {
Name :{
Value: 'Some Value',
DisplayName: "Name"
},
Name1 :{
Value: 'Some Other Value',
DisplayName: "Name"
},
Name2 :{
Value: 'Some Third Value',
DisplayName: "Name"
}
}
};
How can I manage this object properties?
I managed to figure out how to add properties if they don't exist:
function addProperty(name) {
if (!list.Items.hasOwnProperty(name)) {
list.Items[name] = '';
}
};

First of all, your new property is an object, not a blank string, so that at least should have been
function addProperty(name) {
if (!list.Items.hasOwnProperty(name)) {
list.Items[name] = {};
}
};
Furthermore, you have all the methods right there you need, just create an else part and numerically increment the name until you find one that does not exist:
function addProperty(name) {
if (!list.Items.hasOwnProperty(name)) {
list.Items[name] = {};
}
else{
var i = 1;
while(list.Items.hasOwnProperty(name + i)){
i++;
}
list.Items[name + i] = {};
}
};

You could check if the wanted name is a keys of the item property. If true, then it could be used.
function checkIsFree(item) {
return !(item in list.Items);
}
var list = { ListId: '', Items: { Name: { Value: 'Some Value', DisplayName: "Name" }, Name1: { Value: 'Some Other Value', DisplayName: "Name" }, Name2: { Value: 'Some Third Value', DisplayName: "Name" } } };
document.write(checkIsFree('Name5') + '<br>'); // true
document.write(checkIsFree('Name2') + '<br>'); // false

Try this:
var indexes = {};
function addProperty(name, value) {
if (!list.Items.hasOwnProperty(name)) {
list.Items[name] = value;
} else {
indexes[name] = indexes[name]+1 || 1;
list.Items[name + indexes[name]] = value;
}
};

Code below shall perform desired action:
function addProperty(obj, name) {
if (!obj.Items.hasOwnProperty(name)) {
obj.Items[name] = '';
return true
}
return false
};
function addIndexedProperty(obj, name){
var i = 1;
var originName = name;
while (!addProperty(obj, name)){
name = originName + i;
i++;
}
return obj
}
var list = {
ListId: '',
Items: {}
};
addIndexedProperty(list, 'Name');
addIndexedProperty(list, 'Name');
addIndexedProperty(list, 'Name');
console.log(list['Items']); // Object {Name: "", Name1: "", Name2: ""}
Good Luck !

Use recursion to add suffix. Use hasOwnProperty to find if a key exists.
Algorithm
Function takes name,value and length as arguments. Length initially is 0.
When the supplied key already exists, it increments the length and checks if the (name+length) key exists.
If it does not exist, it recursively calls itself with the arguments (name+length,value,0). This will add the key to the list.
If the (name+length) key does not exist, the length is incremented and the the function is called with (name,value,length). This goes on.
If the key does not exist, it is simply added.
var list = {
ListId: '',
Items: {
Name: {
Value: 'Some Value',
DisplayName: "Name"
},
Name1: {
Value: 'Some Other Value',
DisplayName: "Name"
},
Name2: {
Value: 'Some Third Value',
DisplayName: "Name"
}
}
};
function addProperty(name, value, length = 0) {
if (list.Items.hasOwnProperty(name)) {
length++;
if (list.Items.hasOwnProperty(name + length)) {
return addProperty(name, value, length);
} else {
return addProperty(name + length, value, 0);
}
} else {
return list.Items[name] = value;
}
};
addProperty('this_argument_does_not_exist_yet', 'val');
addProperty('Name', 'val');
addProperty('Name', 'val');
addProperty('Name', 'val');
addProperty('Name1', 'val');
console.log(list);
document.getElementById('mypre').innerHTML = JSON.stringify(list,null,2);
<pre id="mypre"></pre>

Related

How to set the property of an object in an array returned by a getter?

With this example:
var data = {
get names() {
return [
{ name: "name1" },
{ name: "name2" },
{ name: "name3" },
]
}
}
data.names[1].name = "Yossi";
console.log (data.names[1]);
The second object in the names array - does not get set by the assignment line (it still logs "name2").
I also tried adding a "setter" straight to the second object:
{
set name(newname) { this.name = newname; },
name: "name2"
}
Same result.
How can I set any of the object's properties in the names array to something else, in a way that works...?
try this:
var data = {
_names: [{ name: "name1" }, { name: "name2" }, { name: "name3" }],
get names() {
return this._names;
},
set names(list) {
this._names = list;
}
};
const names = [...data.names];
names[1].name = "Yossi";
data.names = names;
console.log(data.names[1]);

Create unique values from duplicates in Javascript array of objects

I have an array of duplicated objects in Javascript. I want to create an array of unique objects by adding the index of occurrence of the individual value.
This is my initial data:
const array= [
{name:"A"},
{name:"A"},
{name:"A"},
{name:"B"},
{name:"B"},
{name:"C"},
{name:"C"},
];
This is expected end result:
const array= [
{name:"A-0"},
{name:"A-1"},
{name:"A-2"},
{name:"B-0"},
{name:"B-1"},
{name:"C-0"},
{name:"C-1"},
];
I feel like this should be fairly simple, but got stuck on it for a while. Can you please advise how I'd go about this? Also if possible, I need it efficient as the array can hold up to 1000 items.
EDIT: This is my solution, but I don't feel like it's very efficient.
const array = [
{ name: "A" },
{ name: "A" },
{ name: "C" },
{ name: "B" },
{ name: "A" },
{ name: "C" },
{ name: "B" },
];
const sortedArray = _.sortBy(array, 'name');
let previousItem = {
name: '',
counter: 0
};
const indexedArray = sortedArray.map((item) => {
if (item.name === previousItem.name) {
previousItem.counter += 1;
const name = `${item.name}-${previousItem.counter}`;
return { name };
} else {
previousItem = { name: item.name, counter: 0};
return item;
}
});
Currently you are sorting it first then looping over it, which may be not the most efficient solution.
I would suggest you to map over it with a helping object.
const a = [{name:"A"},{name:"A"},{name:"A"},{name:"B"},{name:"B"},{name:"C"},{name:"C"},], o = {};
const r = a.map(({ name }) => {
typeof o[name] === 'number' ? o[name]++ : o[name] = 0;
return { name: `${name}-${o[name]}` };
});
console.log(r);
Keep a counter, and if the current name changes, reset the counter.
This version mutates the objects. Not sure if you want a copy or not. You could potentially sort the array by object name first to ensure they are in order (if that's not already an existing precondition.)
const array = [
{ name: "A" },
{ name: "A" },
{ name: "A" },
{ name: "B" },
{ name: "B" },
{ name: "C" },
{ name: "C" },
];
let name, index;
for (let i in array) {
index = array[i].name == name ? index + 1 : 0;
name = array[i].name;
array[i].name += `-${index}`;
}
console.log(array);
Another way, if you don't want to sort, and don't want to mutate any objects, is to use a map and keep track of the current index for each object.
const array = [
// NOTE: I put the items in mixed up order.
{ name: "A" },
{ name: "C" },
{ name: "A" },
{ name: "B" },
{ name: "A" },
{ name: "C" },
{ name: "B" },
];
let index = {};
let next = name => index[name] = index[name] + 1 || 0;
let result = array.map(obj => ({ ...obj, name: obj.name + '-' + next(obj.name) }));
console.log(result);

Function variables as object field selector

I have the following function:
populateClinicRoomSelect(object) {
var selectArray = [];
var options = [];
for(var key in object) {
if(object.hasOwnProperty(key)) {
options = {
value: object[key].id,
label: object[key].RoomName,
};
selectArray = selectArray.concat(options);
}
}
return selectArray;
}
The idea is that takes two defined fields from the object array and places it in a new array. It works fine. I also have a few more functions exactly the same to this except the 'id' field and 'RoomName' field are different field names. Is there any way to pass 'id' and 'RoomName' as function variables to define them in the function?
Sure, you can pass field names as arguments and use [arg] accessors as you already do with [key]:
function populateClinicRoomSelect(object, valueField, labelField) {
var selectArray = [];
var options = [];
for(var key in object) {
if(object.hasOwnProperty(key)) {
options = {
value: object[key][valueField],
label: object[key][labelField],
};
selectArray = selectArray.concat(options);
}
}
return selectArray;
}
const object = {
a: {
id: 1,
room: 'first room'
},
b: {
id: 2,
room: 'second room'
}
}
const result = populateClinicRoomSelect(object, 'id', 'room');
console.log(result)
You mean like this?
function populateClinicRoomSelect(object, value, label) {
value = value || "id"; // defaults value to id
label = label || "RoomName"; // defaults label to RoomName
var selectArray = [];
var options = [];
for(var key in object) {
if(object.hasOwnProperty(key)) {
options = {
value: object[key][value],
label: object[key][label],
};
selectArray = selectArray.concat(options);
}
}
return selectArray;
}
let obj = { 1: { id:1, RoomName: "Blue Lounge" }, 2: { id:2, RoomName: "Red Lounge" } }
console.log(populateClinicRoomSelect(obj, 'id', 'RoomName'));

javascript filter by object key and return value of nested object key

I want to return the value of a key for one of the elements inside the object using a condition:
const raw = {
item1: { name: 'sdfd1', otherStuff: { book:'sdfd11' } },
item2: { name: 'sdfd2', otherStuff: { book:'sdfd22' } },
item3: { name: 'sdfd3', otherStuff: { book:'sdfd33' } }
};
var anotherOne = {
country1 : { city: 'one', item: 'item3'},
country2 : { city: 'two', item: 'item4'}
}
var searchTerm = anotherOne.country1.item; // item3
var secondTerm = someUser.otherInfo // 'otherStuff'
var result = Object.keys(raw)
.filter(key => {
if (key === searchTerm){
return raw[searchTerm][secondTerm].book
}})
console.log('result:' result); // sdfd33
Basically, i want to look for the searchTerm in the keys of the object raw, and return the value for the book key. In this example, it should return sdfd33.
My attempt is returning nothing.
updated:
updated the question.
Use square bracket [] while accessing a object key through a variable.
Hopefully the filter & Object.keys will not be required in this case
const raw = {
item1: {
name: 'sdfd1',
book: 'sdfd11'
},
item2: {
name: 'sdfd2',
book: 'sdfd22'
},
item3: {
name: 'sdfd3',
book: 'sdfd33'
}
};
var searchTerm = 'item3';
//using square bracket when acceing key using variable
var result = raw[searchTerm].book
console.log(result);
You can simply return the value like :
var result = raw.item3.book;
console.log(result);
result should be sdfd33

create child objects if they don't exist

For example I have object:
person = {
Name: 'John',
Address: {
Name: 'NY'
}
}
and I have array of properties:
0: Name,
1: Address.Name,
2: Car.Name
I want to create all properties(object) if they don't exist. For example above, I want to get:
{
Name: 'John',
Address: {
Name: 'NY'
},
Car: {
Name: null
}
}
PS. The array is dynamically builded. I don't know which properties there are.
To add missing properties, you can iterate through the properties, check if it is present in the object and add as required.
// original object
var person = {
Name: 'John',
Address: {
Name: 'NY'
}
};
// list of all properties
var props = ['Name', 'Address.Name', 'Car.Name'];
// iterate through the properties and add as needed
props.forEach(function(prop) {
var root = person;
prop = prop.split('.'); // split by . to use [] notation subsequently
for(var i=0; i<prop.length; i++) {
if(typeof root[prop[i]] === 'undefined') root[prop[i]] = (i === prop.length-1 ? null : {});
root = root[prop[i]];
}
});
console.log(person);
/*
{
Name: 'John',
Address: {
Name: 'NY'
},
Car: {
Name: null
}
}
*/
You could first create an object with all the properties set to null, and then use $.extend to merge them together.
obj = {
Name: null,
Addess: {
Name: null
},
Car: {
Name: null
}
};
person = {
Name: 'John',
Addess: {
Name: 'NY'
}
};
person = $.extend(true,obj,person);
I dont understand why you need that but as i understand its useless.
If you need that to validate if value is set you can do simply
var result = (person.Address && person.Address.Name) //true will be returned if address and address name are not null and defined.
If particular property is not yet created typeof will return undefined . you can make use of that to create new property.
if(typeof Car.Name === "undefined")
Car.Name = null; //initialize to some value

Categories

Resources