I have an array of objects that presents as follows:
0: Object
ConsolidatedItem_catalogId: "080808"
ConsolidatedItem_catalogItem: "undefined"
ConsolidatedItem_cost: "0"
ConsolidatedItem_description: "Test Catalog Item"
ConsolidatedItem_imageFile: "27617647008728.jpg"
ConsolidatedItem_itemNumber: "1234"
ConsolidatedItem_quantity: "1"
ConsolidatedItem_source: "CAT"
ConsolidatedItem_status: "02"
ConsolidatedItem_umCode: "EA"
1: Object
ConsolidatedItem_catalogId: ""
ConsolidatedItem_catalogItem: "undefined"
ConsolidatedItem_cost: "0"
ConsolidatedItem_description: "ALARM,SHUTDOWN SYSTEM,AXIOM,XP3, 0-1500 PSIG, HIGH AND LOW PRES Testing"
ConsolidatedItem_imageFile: ""
ConsolidatedItem_itemNumber: "10008"
ConsolidatedItem_quantity: "1"
ConsolidatedItem_source: "INV"
ConsolidatedItem_status: "02"
ConsolidatedItem_umCode: "EA"
I'm trying to update and remove an object if it's added again, or update the object. Preferably update the object with the new value. My code is as follows:
var result = $.grep(finalObject, function(e) {
return e.ConsolidatedItem_itemNumber == o.ConsolidatedItem_itemNumber;
});
console.log(result);
if (result.length == 0) {
finalObject.push(o);
shoppingCounter = finalObject.length;
$('#numberShoppedItems').text(shoppingCounter);
console.log(finalObject);
} else if (result.length == 1) {
finalObject.filter(function(x){
result = x;
console.log(result);
return x == result.ConsolidatedItem_itemNumber;
});
} else {
alert('Multiples Found');
}
}
I've tried multiple ways of getting the exact object and manipulating the data, however they've all failed. I would prefer to update the object, say if CatalogItem_itemNumber held the same value, if the CatalogItem_quantity was different - add the CatalogItem_quantity values together and update the array of objects.
I don't need an exact answer, a nudge in the right direction would do wonders though. I've looked at several of the related questions over the past couple of hours but none of them seem to address the issue. If you know of a question that has an answer, feel free to just link that as well. I may have missed it.
No Underscore.js please
When you find the matching record, you may update it by using $.extend
$.extend(result[0], o)
This will update the object in finalObject array in-place.
Alternatively, if you want to use the filter, you will need to insert the new object in the array.
finalObject = finalObject.filter(function(x) {
return x !== result[0];
});
finalObject.push(o)
Here we are allowing all the records that are not not equal to result to be returned in the resultant array that is received in finalObject. In next line, we are adding the new record.
Solved in the following manner:
1.) Verify object is not empty.
2.) Use .some() on object to iterate through it.
3.) Check if the finalObject, which is now e, has a match for the key in my temporary object I assemble, o.
4.) Update the values that need updating and return true;
Note: Originally I was going to remove the object by its index and replace it with a new object. This too can work by using .splice() and getting the index of the current object in that array you're in.
Here is the updating version:
if (o.ConsolidatedItem_quantity != '') {
var result = $.grep(finalObject, function(e) {
return e.ConsolidatedItem_itemNumber == o.ConsolidatedItem_itemNumber;
});
if (result.length == 0) {...}
else {
finalObject.some(function (e) {
if(e.ConsolidatedItem_itemNumber == o.ConsolidatedItem_itemNumber){
var a;
a = +e.ConsolidatedItem_quantity + +o.ConsolidatedItem_quantity;
e.ConsolidatedItem_quantity = a.toString();
document.getElementById(o.ConsolidatedItem_itemNumber).value=a;
return true;
};
});
}
}
Related
I have an array of nested objects and I have a user, which searches for a room
Here is an array of objects.
I would like to filter an array as soon as user types something
I tried a lot of functions, but nothing worked for me, here is the last example, which failed
search(val: any) {
// if input is clear - show everything, what we have
if (val === '') {
this.roomList = this.roomList;
} else {
//choose the object (objects) where rName = val
this.roomList = this.roomList.staticData.rName.filter(function(o) {
return Object.keys(o).some(function(k) {
return o[k].toString().toLowerCase().indexOf(val) != -1;
})
});
}
}
Could you please help or give me a hint?
You need to apply Array.filter() on roomList instead of staticData propety
this.roomList = this.roomList.filter(function (r) {
return r.staticData.rName.toLowerCase().indexOf(val.toLowerCase()) != -1
});
this.roomList = this.roomList.staticData.rName
This is a wrong starting point, just look at it. Then, rName is not an array, so you can't invoke .filter on it.
Here's how to do it :
this.roomListFiltered = this.roomList.filter(o => new RegExp(val,"i").test(o.staticData.rName) )
new RegExp(val,"i") performs a case-insensitive match.
Also, store the result of the filter in a different variable, otherwise you will lose your original list as it gets filtered out.
I've done some research on this issue. I am trying to manipulate an array of calculated values that looks like this in the console:
{nodeVoltages: Array(11), totalPower: Array(1), xlength: Array(11)}
nodeVoltages: Array(11)
0:48
1:47.71306060387108
2:47.250273223993105
3:46.59686907269243
4:45.71876416434013
5:44.53304242029258
6:42.745236969423615
7:Complex {re: 40.38334500994142, im:1.919295696316476, __ember1513267958317: "ember368"}
8:Complex { re:39.55961661806138, im:3.8933604519196416, __ember1513267958317: "ember369"}
This array is created dynamically through some math that I've come up with so there is no input data that I can give you. I'm trying to make the above array look like this:
{nodeVoltages: Array(11), totalPower: Array(1), xlength: Array(11)}
nodeVoltages: Array(11)
0:48
1:47.71306060387108
2:47.250273223993105
3:46.59686907269243
4:45.71876416434013
5:44.53304242029258
6:42.745236969423615
7:40.38334500994142
8:39.55961661806138
Using mathjs, I was able to evaluate my expressions and dynamically add the values into an array with the array.push command and display them. However, my code breaks once the imaginary values pop up in the results of my array.
How can I remove these imaginary numbers from my array? In other words, I need to remove the "im:" parts of the values when they begin to appear before I push them to the displayed array.
I tried to do this with some code I found from a previous answer to someone else's question (How do I remove a particular element from an array in JavaScript?) splice command like this:
var nodeVoltage2 = parser.eval(expression2);
//checks if there are imaginary values and removes them
if ("im" in nodeVoltage2) {
nodeVoltage2.splice(2,1)
}
//adds value to result array for analysis
nodeVoltages.push(nodeVoltage2);
but it returns in the console that "im is not defined".
Any help is greatly appreciated!
You can use the array map function.
Basically, we loop through the array. If the item has a .re property, we take that value only. If there is no .re property, we keep the value as is.
We can either write that in shorthand, as with result using the ternary operator and arrow function, or we can write it in a slightly more verbose but traditional way, as with resultTwo
let data = [
48
,47.71306060387108
,47.250273223993105
,46.59686907269243
,45.71876416434013
,44.53304242029258
,42.745236969423615
,{re: 40.38334500994142, im:1.919295696316476, __ember1513267958317: "ember368"}
,{ re:39.55961661806138, im:3.8933604519196416, __ember1513267958317: "ember369"}
]
let result = data.map((x) => x && x.re ? x.re : x);
let resultTwo = data.map(function(elem) {
// First, we need to check that the array element is not null / undefined
// We then need to check that it has a property called re that is also not null / undefined
if (elem != null && elem.re != null) {
// Just return the property we're interested in
return elem.re;
} else {
// Return the element as is
return elem;
}
});
console.log(result);
console.log(resultTwo);
In my Angular app I have a function that drills down to an array, and then uses a filter function to pull out values in a new array where "completed" is "false".
This is working as expected. And the way our data is, there is always one object in the array that has the property for "completed" set to "false", so I can target [0] to get to that. So, from there all I need to do is set it to "true". However, for whatever reason, how to accomplish this last step is eluding me.
This is my whole function, and what I've tried thus far:
private completeLastWorkflowStatus() {
let currentService = this.checkDiscipline();
for (let service of this.client.services) {
if (service.service === currentService) {
let targetWorkflow = service.workflow;
let inCompleteWorkflow = targetWorkflow.filter(workflow => workflow.completed === false);
console.log(inCompleteWorkflow);
if (inCompleteWorkflow[0].completed === false) {
inCompleteWorkflow[0].completed === true;
console.log(inCompleteWorkflow[0].completed);
}
}
}
}
For the last console.log listed above, I still get "false" as the value. What am I missing here? How can I set the value of "completed" to "true" for this one object in the array?
inCompleteWorkflow[0].completed === true; is not assignment. Do inCompleteWorkflow[0].completed = true;
I have this algorithme issue, I would like to check if an Object is already present in my Array before adding it.
I tried many different approaches (indexOf, filter...), and my last attempt is with an angular.foreach.
The problem is my $scope.newJoin remains always empty. I understood why, it's because the if is never read, because of the 0 size of my $scope.newJoin, but I don't know how to figure this out...
$scope.newJoinTMP is composed by : 6 Objects, within each a timePosted attribute (used for compare these different array Objects).
$scope.newJoin is an empty Array. I want to fill it with the Objects inside $scope.newJoinTMP but with the certainty to have once each Objects, and not twice the same ($scope.newJoinTMP can have duplicates Objects inside, but $scope.newJoin mustn't).
angular.forEach($scope.newJoinTMP, function(item)
{
angular.forEach($scope.newJoin, function(item2)
{
if (item.timePosted === item2.timePosted)
{
//snap.val().splice(snap.val().pop(item));
console.log("pop");
}
else
{
$scope.newJoin.push(item);
console.log("newJoin :", $scope.newJoin);
}
});
});
if(!$scope.newJoin.find(el=>item.timePosted===el.timePosted){
$scope.newJoin.push(item);
console.log("newJoin :", $scope.newJoin);
}
You dont want to push inside an forEach, as it will push multiple times...
There might be better ways to handle your particular situation but here's a fix for your particular code.
Replaced your inner for each with some which returns boolean for the presence of element and by that boolean value, deciding whether to add element or not
angular.forEach($scope.newJoinTMP, function(item)
{
var isItemPresent = $scope.newJoin.some(function(item2)
{
return item.timePosted === item2.timePosted;
//you dont need this conditional handling for each iteration.
/* if (item.timePosted === item2.timePosted)
{
//snap.val().splice(snap.val().pop(item));
console.log("pop");
}
else
{
$scope.newJoin.push(item);
console.log("newJoin :", $scope.newJoin);
} */
});
if( ! isItemPresent ) {
$scope.newJoin.push(item);
} else {
//do if it was present.
}
});
If you want to avoid the nested loop (forEach, some, indexOf, or whatever) you can use an auxiliar object. It will use more memory but you will spent less time.
let arr = [{ id: 0 }, { id:0 }, { id: 1}];
let aux = {};
const result = arr.reduce((result, el) => {
if (aux[el.id] === undefined) {
aux[el.id] = null;
return [el, ...result];
} else {
return result;
}
}, []);
console.log(result);
You can use reduce
$scope.newJoin = $scope.newJoinTMP.reduce(function(c, o, i) {
var contains = c.some(function(obj) {
return obj.timePosted == o.timePosted;
});
if (!contains) {
c.push(o);
}
return c;
}, []);
The problem with your current code is, if newJoin is empty, nothing will ever get added to it - and if it isnt empty, if the first iteration doesn't match the current item being iterated from newJoinTMP - you're pushing.
I have data of this form (simplified, but assume 20 columns between Admin and Mining):
Date,Series,Admin,Mining,CPI
1990,Ordinary Time Earnings,20,30,96
1991,Ordinary Time Earnings,22,33,100
1990,Total Earnings,25,38,96
1991,Total Earnings,29,43,100
Which I separate out into two series like this:
d3.csv("avgearnings_v1_1.csv", function(error, data) {
if (error) throw error;
OrdinaryTimeEarnings = data
.filter(function(d) {
if(d.Series == 'Ordinary Time Earnings')
return d;
});
TotalEarnings = data
.filter(function(d) {
if(d.Series == "Total Earnings")
return d;
});
And can get that to display on a graph without any issue. What I want to do next is create two more series:
OrdinaryTimeEarningsReal = OrdinaryTimeEarnings;
TotalEarningsReal = TotalEarnings;
And then recalculate those new series. Basically:
For any column that is not Date/Series/CPI
Take the CPI value for that year
Individually divide each of the Mining-Admin columns by the CPI and multiply by 100.
So: New Value = ([Old Value]/[CPI])*100
My code is terrible but I can get the correct values using this:
OrdinaryTimeEarningsReal
.forEach(function (z,i) {
var CPI = z["CPI"];
d3.map(z, function(b) {return b;})
.forEach(function (c) {
if(c !== "Date" && c !== "Series" && c !== "CPI" )
OrdinaryTimeEarningsReal[i][c] = ((z[c])/(CPI))*100;
});
});
But, when I do this it is somehow also updating the original OrdinaryTimeEarnings series, such that they equal each other and the original data in OrdinaryTimeEarnings is lost.
I'm not sure whether it's the fact I'm using the bare object (while iterating within it, eek!) or that the code above is actually changing the values in the original data object (and all 4 of the series I've created after are just references to it).
Either way, I can't work it out! I've tried a fair few different syntax forms but can't work it out. Help would be greatly appreciated to achieve this.
If you indeed use this code to "duplicate" your arrays:
OrdinaryTimeEarningsReal = OrdinaryTimeEarnings;
TotalEarningsReal = TotalEarnings;
then you mentioned it right, when you said that they reference the same object. In JavaScript, arrays are mutable, and using the code above you just created 2 new variables with a reference to the existing array in the memory.
In order to deep clone your array of objects, use this method:
OrdinaryTimeEarningsReal = JSON.parse(JSON.stringify(OrdinaryTimeEarnings));
TotalEarningsReal = JSON.parse(JSON.stringify(TotalEarnings));
This will create duplicates of the array and assign them to the new variables, so that when you'll edit them, the initial arrays will remain unaffected.
Now, regarding your code, it's a bit too complex. If I understood correctly what are you trying to achieve, you could simplify it as follows:
OrdinaryTimeEarningsReal
.forEach(function (z,i) {
for (var c in z) {
if (z.hasOwnProperty(c) && c !== "Date" && c !== "Series" && c !== "CPI" )
z[c] = z[c] / z.CPI * 100;
});
});
Good luck!
If I understand correctly :
data.forEach(function(d) {
for (var key in d) {
if (key !== 'Date' && key !== 'Series' && key !== 'CPI') {
d['new' + key] = (d[key] / d.CPI) * 100;
}
}
})
console.log(data)
I have added new onto the new attributes so the new admin value is newAdmin
Implemented fiddle : https://jsfiddle.net/thatOneGuy/9ywLytjf/