Updating an array of objects in javascript - javascript

I have an array of javascript objects like the following:
var food = [
{id: 1, name: 'Apples', owned: true },
{id: 2, name: 'Oranges', owned: false },
{id: 3, name: 'Bananas', owned: true }
];
Then I receive another array with the following data:
var newFood = [
{id: 1, name: 'Peas'},
{id: 2, name: 'Oranges'},
{id: 3, name: 'Bananas'},
{id: 4, name: 'Grapefruits'}
];
How can I update the previous food array with the new information in newFeed, without overwriting the original owned property, while adding an owned: false to any new object?
Keep in mind this is plain javascript, not jQuery.

You'd probably want to index food by id so make food an object instead of an array:
var food = {
1: {name: "Apples", owned: true},
//...
}
then iterate over newFood and update the fields appropriately.

I think you can use underscore.js for fix the problem.
var arrayObj = [
{Name:'John',LastName:'Smith'},
{Name:'Peter',LastName:'Jordan'},
{Name:'Mike',LastName:'Tyson'}
];
var element = _.findWhere(arrayObj, { Name: 'Mike' });
element.Name="SuperMike";
console.log(arrayObj);

This works:
var temp = {};
for (var i = 0, l = food.length; i < l; i += 1) {
temp[food[i].name] = true;
}
for (var i = 0, l = newFood.length; i < l; i += 1) {
if ( !temp[newFood[i].name] ) {
food.push( { id: food.length + 1, name: newFood[i].name, owned: false });
}
}
The first for statement will populate the temp object with the fruit names from the food array, so that we know which fruits exist in it. In this case, temp will be this:
{ "Apples": true, "Oranges": true, "Bananas": true }
Then, the second for statement checks for each fruit in newFood if that fruit exists in temp, and if it doesn't, if pushes a new array item into the food array.

some thing like this? JSFiddle Example
JavaScript
function updateFood( newFood, oldFood ) {
var foodLength = oldFood.length - 1;
for (var i = 0; i < newFood.length; i++) {
if (i > foodLength) { //add more if needed
newFood[i].owned = false;
oldFood.push(newFood[i]);
} else if (!food[i].owned) { //replace if needed
newFood[i].owned = false;
oldFood[i] = newFood[i];
}
}
}

Related

Filter the object depending on the field's value in javascript

I'm kinda new to javascript. Here I have the following object:
obj = {
0:{id:1, location: loc1, title:title1},
1:{id:2, location: loc2, title:title2},
2:{id:3, location: loc1, title:title3},
3:{id:4, location: loc3, title:title4},
4:{id:5, location: loc1, title:title5}
}
What I need is to filter the object by location depending on its value and create a new object like the following:
obj = {
loc1:{
0:{id:1, location: loc1, title:title1},
1:{id:3, location: loc1, title:title3},
2:{id:5, location: loc1, title:title5}
},
loc2:{
0:{id:2, location: loc2, title:title2}
}
loc3:{
0:{id:4, location: loc3, title:title4}
}
}
How can I achieve the above object?
I tried using for and push to a new array but the location should be dynamic and may change in the future and I want to have one object to manage like above.
var theLoc1 = [], theLoc2 = [];
for(var i = 0; i < response.length; i++) {
if(response[i].location == 'loc1'){
theLoc1.push(response[i]);
}else if(response[i].location == 'loc2'){
theLoc2.push(response[i]);
}
}
This Code is what u really need:
obj = [
{ id: 1, location: 'loc1', title: 'title1' },
{ id: 2, location: 'loc2', title: 'title2' },
{ id: 3, location: 'loc1', title: 'title3' },
{ id: 4, location: 'loc3', title: 'title4' },
{ id: 5, location: 'loc1', title: 'title5' }
];
var locations = {};
for (var i = 0; i < obj.length; i++) {
locations[obj[i].location] = [];
}
console.log(locations);
for (var i = 0; i < obj.length; i++) {
locations[obj[i].location].push(obj[i]);
}
console.log(locations);
**Update:It Can be done in a single for loop but for simplicity reasons i wrote it like this. **
let obj;
for(var i = 0; i < response.length; i++) {
if( !Object.hasOwnProperty(obj, response[i].location)
{ obj[response[i].location] = []; }
obj[response[i].location].push(response[i]);
}
You can dynamically create JS object properties if you just address them. This means:
let obj = {};
obj.bark = "how-how";
console.log(obj.bark); // "how-how";
obj[bark2] = "waf-waf";
console.log(obj.bark2); // "waf-waf";
you can use it to struct your new object with the locations names, so even if someday you get "location999" it'll still work.
I put the if that checks if the object laready has that property because you want the property to be an array. If it wasn't you could've just put the value inside like in my example, but im not sure if push would work on it so I initialize it to be empty array just in case. You can check it yourself and ommit the if if its not needed.
My solution using functional programming.
const obj = {
0: { id: 1, location: 'loc1', title: 'title1' },
1: { id: 2, location: 'loc2', title: 'title2' },
2: { id: 3, location: 'loc1', title: 'title3' },
3: { id: 4, location: 'loc3', title: 'title4' },
4: { id: 5, location: 'loc1', title: 'title5' }
};
const result = Object.keys(obj).reduce((newObject, item) => {
const location = obj[item].location;
const index = newObject[location] ? Object.keys(newObject[location]).length : 0;
return {
...newObject,
[location]: {
...newObject[location],
[index]: obj[item]
}
};
}, {});
console.log(result);
In order to group your items by location you can iterate your array, see whether its location was already grouped and if not, create a new group for it. Afterwards add the item to the corresponding group.
var obj = [
{id: 1, location: "loc1", title: "title1"},
{id: 2, location: "loc2", title: "title2"},
{id: 3, location: "loc1", title: "title3"},
{id: 4, location: "loc3", title: "title4"},
{id: 5, location: "loc1", title: "title5"}
];
var formattedArray = new Array();
for (var i = 0; i < obj.length; i++) {
if (!formattedArray[obj[i].location]) {
formattedArray[obj[i].location] = new Array();
}
formattedArray[obj[i].location].push(obj[i]);
}
console.log(formattedArray);
JsFiddle example code:
JsFiddle
You can try the following if your loc1, loc2, loc3 are fixed. (That is what I understood after reading your query)
var response = [
{id:1, location: "loc1", title:"title1"},
{id:2, location: "loc2", title:"title2"},
{id:3, location: "loc1", title:"title3"},
{id:4, location: "loc3", title:"title4"},
{id:5, location: "loc1", title:"title5"}
]
var resObj = {
published:[],
private: [],
pending:[]
}
for(var i = 0; i < response.length; i++) {
if(response[i].location == 'loc1'){
resObj.published.push(response[i]);
}else if(response[i].location == 'loc2'){
resObj.private.push(response[i]);
}else {
resObj.pending.push(response[i]);
}
}
console.log(resObj)
I think the better way to do this, is to group your objects already in your backend. You can use the linq function .GroupBy(x => x.location).
This is near the same problem:
How to count rows of a table grouped by shortdatestring?
// create an array of arrays;
var groupOfLocations[];
// loop on your locations
for(var i = 0; i < response.length; i++) {
// push if already existing
for(var iGroup = 0; iGroup < groupOfLocations.length; iGroup++) {
if(groupOfLocations[iGroup][0].location == response[i].location) {
groupOfLocations[iGroup].push(response[i]); break;
}
// create a new array if not found
if(iGroup >= groupOfLocations.length) groupOfLocations.push(new array(response[i]));
}
May contains syntax mistakes, but the idea is here.

problems with for loop inside another for loop Javascript

I have problems in going through these two for loops, I need to get the same elements from the first array within the cycle, but the values ​​are being repeated. I know that they are repeated depending on the data of the second array.
I tried to make comparisons but I could not get the result I want.
var array = [
{
grouper: 1
},
{
grouper: 2
},
{
grouper: 3
},
{
grouper: 4
},
];
var array2 = [
{
value: 1,
grouper: 1,
status: 100
},
{
value: 2,
grouper: 2,
status: 100
},
{
value: 3,
grouper: 3,
status: 100
}
];
for(var i = 0; i<array.length; i++){
for(var j = 0; j<array2.length; j++){
if(array2[j].grouper == array[i].grouper){
console.log(array[i].grouper+'-'+array2[j].value);
}
}
}
This is the result I want, I need all the groupers from the first array and the values from the second array:
1-1
2-2
3-3
4-
The grouper 4, does not have value, but I need to show it.
I need the second array because I'm going to compare with the data from the second array
I do not know if I am doing the process wrong. I hope you can help me.
You could simply track if there was a match (variable shown), and if there were not any, display a "half" line:
var array = [{grouper: 1},{grouper: 2},{grouper: 3},{grouper: 4},];
var array2 = [
{value: 1, grouper: 1, status: 100},
{value: 2, grouper: 2, status: 100},
{value: 3, grouper: 3, status: 100}
];
for(var i = 0; i<array.length; i++){
var shown=false;
for(var j = 0; j<array2.length; j++){
if(array2[j].grouper == array[i].grouper){
console.log(array[i].grouper+'-'+array2[j].value);
shown=true;
}
}
if(!shown){
console.log(array[i].grouper+"-");
}
}
First of all, with the example you provided I believe you want to get back:
1,2,3
There is no 4th object inside of array2, so your conditional (array2[j].grouper == array[i].grouper will never evaluate to true.
The question here is whether you are always comparing the same indexes? In this example, you're comparing array[0] to array2[0] to see if grouper in array equals grouper in array2... that's it????
In that case you just do one loop:
for (var i = 0; i < array.length; i++) {
if (array[i].grouper == array2[i].grouper) {
console.log(array[i].grouper+'-'+array2[j].value);
}
}
#FabianSierra ... with your provided example one just needs to handle the not fulfilled if clause/condition in the most inner loop.
A more generic approach additionally might take into account changing field names (keys). Thus a function and Array.reduce / Array.find based approach provides better code reuse. An example implementation then might look similar to that ...
var array = [{ // in order.
grouper: 1
}, {
grouper: 2
}, {
grouper: 3
}, {
grouper: 4
}];
var array2 = [{ // not in the order similar to `array`.
value: 22,
grouper: 2,
status: 200
}, {
value: 33,
grouper: 3,
status: 300
}, {
value: 11,
grouper: 1,
status: 100
}];
function collectRelatedItemValuesByKeys(collector, item) {
var sourceKey = collector.sourceKey;
var targetKey = collector.targetKey;
var targetList = collector.targetList;
var resultList = collector.result;
var sourceValue = item[sourceKey];
var targetValue;
var relatedItem = targetList.find(function (targetItem) {
return (targetItem[sourceKey] === sourceValue);
});
if (typeof relatedItem !== 'undefined') {
targetValue = relatedItem[targetKey];
} else if (typeof targetValue === 'undefined') {
targetValue = ''; // `relatedItem` does not exist.
}
resultList.push([sourceValue, targetValue].join('-'));
return collector;
}
var resultList = array.reduce(collectRelatedItemValuesByKeys, {
sourceKey: 'grouper',
targetKey: 'value',
targetList: array2,
result: []
}).result;
console.log('resultList : ', resultList);
resultList = array.reduce(collectRelatedItemValuesByKeys, {
sourceKey: 'grouper',
targetKey: 'status',
targetList: array2,
result: []
}).result;
console.log('resultList : ', resultList);
.as-console-wrapper { max-height: 100%!important; top: 0; }

Trying to avoid duplicates when creating new array from comparing value of two others

I have an app where I need to create a new array by pushing values from two other arrays after comparing what values in one array exist in another.
Example:
From these two arrays...
sel[1,4];
bus[1,2,3,4,5,6];
The desired result is a new object array which will populate a repeater of checkboxes in my view...
newList[{1:true},{2:false},{3:false},{4:true},{5:false},{6:false}];
The problem I'm running into, is that my code is creating duplicates and I'm not seeing why.
Here is my code:
var newList = [];
var bus = self.businesses;
var sel = self.campaign.data.businesses;
for( var b = 0; b < bus.length; b++ ){
if(sel.length > -1){
for( var s = 0; s < sel.length; s++){
if( bus[b]._id === sel[s].business_id){
newList.push({'business_id':bus[b]._id, 'name':bus[b].business_name, 'selected':true});
} else {
newList.push({'business_id':bus[b]._id, 'name':bus[b].business_name, 'selected':false});
}
}
} else {
console.log('hit else statement');
newList.push({'business_id':bus[b]._id, 'name':bus[b].business_name, 'selected':false});
}
}
I need fresh eyes on this as it looks correct to me... but obviously I'm missing something. :-)
Your code produces duplicates because you push selected: false objects into your newList every time the inner loop is run and the ids don't match:
for( var s = 0; s < sel.length; s++){
if( bus[b]._id === sel[s].business_id){
newList.push({'business_id':bus[b]._id, 'name':bus[b].business_name, 'selected':true});
} else {
// THIS LINE CAUSES THE DUPLICATES:
newList.push({'business_id':bus[b]._id, 'name':bus[b].business_name, 'selected':false});
}
}
To fix your code, move this line out of the inner loop into the outer loop below and add a continue outer; to the inner loop's if body. Then you need to place the outer label directly in front of the outer loop: outer: for( var b = 0; b < bus.length; b++ ) ....
However, I recommend a simpler implementation as follows:
let selection = [{_id: 1, business_name: 'A'}];
let businesses = [{_id: 1, business_name: 'A'}, {_id: 2, business_name: 'B'}];
let result = businesses.map(business => ({
'business_id': business._id,
'name': business.business_name,
'selected': selection.some(selected => business._id == selected._id)
}));
console.log(result);
Appendix: Same implementation with traditional functions:
var selection = [{_id: 1, business_name: 'A'}];
var businesses = [{_id: 1, business_name: 'A'}, {_id: 2, business_name: 'B'}];
var result = businesses.map(function(business) {
return {
'business_id': business._id,
'name': business.business_name,
'selected': selection.some(function(selected) { return business._id == selected._id })
};
});
console.log(result);
I suggest to use a different approach by using an object for sel and the just iterate bus for the new array with the values.
function getArray(items, selected) {
var hash = Object.create(null);
selected.forEach(function (a) {
hash[a] = true;
});
return items.map(function (a) {
var temp = {};
temp[a] = hash[a] || false;
return temp;
});
}
console.log(getArray([1, 2, 3, 4, 5, 6], [1, 4]));
ES6 with Set
function getArray(items, selected) {
return items.map((s => a => ({ [a]: s.has(a) }))(new Set(selected)));
}
console.log(getArray([1, 2, 3, 4, 5, 6], [1, 4]));
You can use map() method on bus array and check if current value exists in sel array using includes().
var sel = [1,4];
var bus = [1,2,3,4,5,6];
var result = bus.map(e => ({[e] : sel.includes(e)}))
console.log(result)
This combines both Nina Scholz elegant ES6 approach with le_m's more specific solution to give you something that is shorter, versatile, and repurposable.
function getArray(items, selected, [...id] = selected.map(selector => selector._id)) {
return [items.map((s => a => ({
[a._id + a.business_name]: s.has(a._id)
}))(new Set(id)))];
}
console.log(...getArray([{
_id: 1,
business_name: 'A'
}, {
_id: 2,
business_name: 'B'
}, {
_id: 3,
business_name: 'C'
}, {
_id: 4,
business_name: 'D'
}, {
_id: 5,
business_name: 'E'
}, {
_id: 6,
business_name: 'F'
}], [{
_id: 1,
business_name: 'A'
}, {
_id: 2,
business_name: 'B'
}]));

Old JSON value Changed

I have two JSON objects columnsData and columns when assigning columnsData value to columns both values are changed.
var columnsData = [
{id: "id"},
{id: "root_task_assignee"},
{id: "root_task_id"},
{id: "root_task_status"},
{id: "root_task_tracker"},
{id: "rt_category"},
{id: "rt_priority"},
{id: "rt_subject"},
]
var columns = [];
using the below function I assigned the columnsData value to columns object, and also added some additional fields
for(i = 0;i < columnsData.length; i++){
columns[i] = columnsData[i];
columns[i]["name"] = columnsData[i]["name"] || columnsData[i]["id"];
columns[i]["type"] = columnsData[i]["id"]["type"] || "string";
}
but after assigning both have the same values. How the old JSON columnsData value was changed? is there any other way to assign values
columns[i] = columnsData[i] does not copy the data, it makes an additional reference to the same data.
For example, say you give Mr. Random Jones a nickname, "Cozy". If you give Cozy an envelope to hold, are you surprised if Mr. Jones is now holding an envelope too?
Same thing here. If you change columns[i], you are also changing columnsData[i], since they are the same object.
You would have to clone it if you wanted to have them be different. In this case, you just have to make a new object with id:
columns[i] = { id: columnsData[i].id };
In general, you would do well to find a nice clone function.
If it is required to keep original array pure (unchanged) we should use map method of array.
var columnsData = [
{id: "id"},
{id: "root_task_assignee"},
{id: "root_task_id"},
{id: "root_task_status"},
{id: "root_task_tracker"},
{id: "rt_category"},
{id: "rt_priority"},
{id: "rt_subject"},
]
var columns = columnsData.map(function(obj){
var rObj = {};
rObj[obj.key] = obj.value;
rObj["name"] = obj.value;
.....
return rObj;
});
Logic can be added in map method to create new array as required. Hope it helps.
columns[i] = columnsData[i] will not copy content from one object to another but it will an reference of the columnsData[i]. As they are refereeing to same object, change in property of one object will affect the primary object which is being refereed.
Try this:
var columnsData = [{
id: "id"
}, {
id: "root_task_assignee"
}, {
id: "root_task_id"
}, {
id: "root_task_status"
}, {
id: "root_task_tracker"
}, {
id: "rt_category"
}, {
id: "rt_priority"
}, {
id: "rt_subject"
}, ]
var columns = [];
for (i = 0; i < columnsData.length; i++) {
var obj = {};
obj["name"] = columnsData[i]["name"] || columnsData[i]["id"];
obj["type"] = columnsData[i]["id"]["type"] || "string";
columns.push(obj)
}
alert(JSON.stringify(columns));
alert(JSON.stringify(columnsData));

Javascript: A fast way to check if an element is in a two-dimensional array?

I have a nodes_object array, which has the structure of the following kind:
nodes_object = {
1: {
source: '001',
name: 'A',
target: '004',
name: 'B'
},
2: {
source: '003',
name: 'C',
target: '001',
name: 'A'
},
}
Then I also have an array sorted which is structured in the following way:
sorted = {
1: {
val: '001',
count: '100'
},
2: {
val: '003',
count: '80'
}
I need to create a function, which would reiterate through the nodes_object, check if BOTH the source and the target are contained in one of the sorted val parameters, and if yes, proceed further.
So far I came up with the function below, which first reiterates through the nodes_object, then reiterates through the sorted to see if any of the elements is present within it, but I'm wondering if there's a faster and a more efficient way to do that?
Thank you!
for (var i = 0; i < nodes_object.length; i++) {
var sourcein = null;
var targetin = null;
for (var j = 0; j < sorted.length; j++) {
if (sorted[j].val == nodes_object[i][0]) {
sourcein = 1;
}
if (sorted[j].val == nodes_object[i][2]) {
targetin = 1;
}
}
if ((sourcein) && (targetin)) {
// Perform the function
}
}
First of all, to create arrays you use [], not {}. So it should be:
nodes_object = [
{
source: '001',
name: 'A',
target: '004',
name: 'B'
},
{
source: '003',
name: 'C',
target: '001',
name: 'A'
},
];
and similarly for sorted.
Make an object whose keys are the val objects you want to test.
hash = {};
for (var k = 0; k < sorted.length; k++) {
hash[sorted[k]] = true;
}
Then you can use in hash to test whether something is found in sorted:
var sourcein, targetin;
for (var i = 0; i < nodes_object.length; i++) {
sourcein = nodes_object[i].source in hash;
targetin = nodes_object[i].target in hash;
if (sourcein && targetin) {
...
}
}

Categories

Resources