Good day
I was wondering if someone can assist me in calculating the sum value of a array of data.
var products = [{'size':'400' },{'size':'500' }] ;
angular.forEach(products, function(item){
var total = 0;
total += item.size++;
return total;
});
How do I use $q.all() statement to store up this information as the file download section am using ignores my angular.forEach statment and just checks individual items instead.
Use reduce instead of angular.forEach
const productSum = products.reduce((sum, product) => sum + parseInt (product.size, 10), 0)
$q.all is for computing multiple promises. I think you are looking in the wrong direction.
if you want to get sum of all sizes then use javascript reduce method. It will return the sum of all sizes efficiently.
var products = [{'size':'400' },{'size':'500' }] ;
var sum = products.reduce((a,b) => parseInt(a.size) + parseInt(b.size))
console.log(sum)
About $q.all. $q.all typically use to send multiple http request one shot. If you want send the sum to your service then bind the sum as data property to one of or all your http requests (depend on your requirement).
Related
I'm trying to automate the collection of phone numbers from an API into a Google Sheet with app script. I can get the data and place it in an array with the following code:
const options = {
method: 'GET',
headers: {
Authorization: 'Bearer XXXXXXXXXXXXXXX',
Accept: 'Application/JSON',
}
};
var serviceUrl = "dummyurl.com/?params";
var data=UrlFetchApp.fetch(serviceUrl, options);
if(data.getResponseCode() == 200) {
var response = JSON.parse(data.getContentText());
if (response !== null){
var keys = Object.keys(response.call).length;
var phoneArray = [];
for(i = 0; i < keys; i++) {
phoneArray.push(response.call[i].caller.caller_id);
}
This works as expected - it grabs yesterday's caller ID values from a particular marketing campaign from my API. Next, I want to import this data into a column in my spreadsheet. To do this, I use the setValues method like so:
Logger.log(phoneArray);
var arrayWrapper = [];
arrayWrapper.push(phoneArray);
Logger.log(arrayWrapper);
for(i = 0; i < keys; i++) {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var cell = sheet.getRange("A8");
cell.setValues(arrayWrapper);
}
}
}
}
I am aware that I need my array length to equal the length of the selected range of cells in my sheet. However, I get conflicting errors depending on the length I set for my getRange method. If I set it to a single cell, as you see above, the error I get is:
The number of columns in the data does not match the number of columns in the range. The data has 8 but the range has 1.
However, if I set the length of my range to 8 (or any value except 1), I get the error:
The number of columns in the data does not match the number of columns in the range. The data has 1 but the range has 8.
As you see, the error swaps values. Now I have the appropriate number of columns in the range, but my script only finds 1 cell of data. When I check the log, I see that my 2D array looks normal in both cases - 8 phone numbers in an array wrapped in another array.
What is causing this error? I cannot find reference to similar errors on SO or elsewhere.
Also, please note that I'm aware this code is a little wonky (weird variables and two for loops where one would do). I've been troubleshooting this for a couple hours and was originally using setValue instead of setValues. While trying to debug it, things got split up and moved around a lot.
The dimension of your range is one row and several columns
If you push an array into another array, the dimension will be [[...],[...],[...]] - i.e. you have one column and multiple rows
What you want instead is one row and multiple columns: [[...,...,...]]
To achieve this you need to create a two-dimensional array and push all entries into the first row of your array: phoneArray[0]=[]; phoneArray[0].push(...);
Sample:
var phoneArray = [];
phoneArray[0]=[];
for(i = 0; i < keys; i++) {
var phoneNumber = response.call[i].caller.caller_id;
phoneNumber = phoneNumber.replace(/-/g,'');
phoneArray[0].push(phoneNumber);
}
var range = sheet.getRange(1,8,1, keys);
range.setValues(phoneArray);
So I figured out how to make this work, though I can't speak to why the error is occurring, or rather why one receives reversed error messages depending on the setRange value.
Rather than pushing the whole list of values from the API to phoneArray, I structured my first for loop to reset the value of phoneArray each loop and push a single value array to my arrayWrapper, like so:
for(i = 0; i < keys; i++) {
var phoneArray = [];
var phoneNumber = response.call[i].caller.caller_id;
phoneNumber = phoneNumber.replace(/-/g,'');
phoneArray.push(phoneNumber);
arrayWrapper.push(phoneArray);
}
Note that I also edited the formatting of the phone numbers to suit my needs, so I pulled each value into a variable to make replacing a character simple. What this new for loop results in is a 2D array like so:
[[1235556789],[0987776543],[0009872345]]
Rather than what I had before, which was like this:
[[1235556789,0987776543,0009872345]]
It would appear that this is how the setValues method wants its data structured, although the documentation suggests otherwise.
Regardless, if anyone were to run into similar issues, this is the gist of what must be done to fix it, or at least the method I found worked. I'm sure there are far more performant and elegant solutions than mine, but I will be dealing with dozens of rows of data, not thousands or millions. Performance isn't a big concern for me.
var correct = [[data],[data]] -
is the data structure that is required for setValues()
therefore
?.setValues(correct)
I have a function that takes in two very large arrays. Essentially, I am matching up orders with items that are in a warehouse available to fulfill that order. The order is an object that contains a sub array of objects of order items.
Currently I am using a reduce function to loop through the orders, then another reduce function to loop through the items in each order. Inside this nested reduce, I am doing a filter on items a customer returned so as not to give the customer a replacement with the item they just send back. I am then filtering the large array of available items to match them to the order. The large array of items is mutable since I need to mark an item used and not assign it to another item.
Here's some psudocode of what I am doing.
orders.reduce(accum, currentOrder)
{
currentOrder.items.reduce(internalAccum, currentItem)
{
const prevItems = prevOrders.filter(po => po.customerId === currentOrder.customerId;
const availItems = staticItems.filter(si => si.itemId === currentItem.itemId && !prevItems.includes(currentItem.labelId)
// Logic to assign the item to the order
}
}
All of this is running in a MESOS cluster on my server. The issue I am having is that my MESOS system is doing a health check every 10 seconds. During this working of the code, the server will stop responding for a short period of time (up to 45 seconds or so). The health check will kill the container after 3 failed attempts.
I am needing to find some way to do this complex looping without blocking the response of the health check. I have tried moving everything to a eachSerial using the async library but it still locks up. I have to do the work in order or I would have done something like async.each or async.eachLimit, but if not processed in order, then items might be assigned the same thing simultaneously.
You can do batch processing here with a promisified setImmediate so that incoming events can have a chance to execute between batches. This solution requires async/await support.
async function batchReduce(list, limit, reduceFn, initial) {
let result = initial;
let offset = 0;
while (offset < list.length) {
const batchSize = Math.min(limit, list.length - offset);
for (let i = 0; i < batchSize; i++) {
result = reduceFn(result, list[offset + i]);
}
offset += batchSize;
await new Promise(setImmediate);
}
return result;
}
I am trying to add information from a map received through an http call to a list of objects in Dart. For example, the list of objects are Tools that have the toollocation property:
Tool(
{this.make,
this.model,
this.description,
this.tooltype,
this.toollocation,
this.paymenttype,
this.userid});
I am also using the google distance matrix api to gather the distance from the user that the tool is.
Future<DistanceMatrix> fetchDistances() async {
await getlocation();
latlongdetails = position['latitude'].toString() +
',' +
position['longitude'].toString();
print(latlongdetails);
print('still running');
final apiresponsepc = await http
.get(
'https://maps.googleapis.com/maps/api/distancematrix/json?units=imperial&origins=$latlongdetails&destinations=$postcodes&key=xxx');
distanceMatrix =
new DistanceMatrix.fromJson(json.decode(apiresponsepc.body));
return distanceMatrix;
}
What I have been doing in the past is calling a future and just getting the distance once I have returned the original results for the tool. However I want to be able to sort the tool results by distance, so I need to iterate through each tool in the list and add the distance for each of them.
So far I have been trying a foreach loop on the tools list:
finalresults.forEach((tool){ tool.toollocation = distanceMatrix.elements[0].distance.text;});
but clearly this will only add the first distance measurement to every one of the tools.
Is there any way I can iterate through each tool and then add the distance from the distance matrix map? Each distance will be in sequence with each tool in the list.
I think this is what you wanted to do
finalResults.forEach((tool) {
distanceMatrix.elements.forEach((element){
tool.toolLocation = element.distance.text;
});
});
If elements is also a List then you can use the foreach syntax to iterate through it.
I have resolved this with the following code:
int number = 0;
finalresults.forEach((tool) {
tool.toollocation = distanceMatrix.elements[number].distance.text;
number = number + 1;
});
I'm looking to take the result of a survey that I created using JSON, add up the values associated with the objects from that survey in order to produce a sum. However, I am unsure of how to call upon the items within the Survey Result
I would apprecaite any help.
Survey Result: {
"Number of Polarization Images":1,
"Possibility of Primes":2,
"Available Layers":2,
"Image Quality":3,
"Lead Rank":3,
"Repairs Report":2,
"Topography":2,
"AOI Size":1,
"Field Verification":2,
"Season":1
}
Use .reduce combined with Object.values for browsers that support it
var sum = Object.values( survey_results_variable ).reduce((p,v)=>p+v,0);
For browsers that do not support Object.values use Object.keys
var sum = Object.keys( survey_results ).reduce((p,v)=>p+survey_results[v],0);
Simple solution is
var sum = 0;
for (k in survey_result) sum += survey_result[k];
The bit you might have been missing was the for...in way of iterating over properties in an object.
I am building a simple Appgyver mobile app using Angularjs and Coffeescript - I'm a beginner with both of these.
I wish to determine the total cost for a list of up to 20 items stored on the database. However, there may be less than 20 items.
I have attempted to do the calculation with ng-bind, which works perfectly as long as all strings contain values. However, if there are less than 20 pairs (values go up to q20 and p20) then the calculation returns NaN.
I would like to determine the total of all existing values for the list. I have looked at numerous examples on stackoverflow, Angularjs.org and other sites and have experimented with a myriad of alternative methods, however I think I lack the basic understanding of how to make this work. Any help would be appreciated.
This is the code I have used, shortened to 3 pairs instead of 20:
<span ng-bind="client['q1'].price * client['p1'].price + client['q2'].price
* client['p2'].price + client['q3'].price * client['p3'].price"></span>
This is the existing controller:
angular
.module('client')
.controller("ShowController", ($scope, Client, supersonic) ->
$scope.client = 0;
$scope.showSpinner = true
$scope.dataId = undefined
_refreshViewData = ->
Client.find($scope.dataId).then (client) ->
$scope.$apply ->
$scope.client = client
$scope.showSpinner = false
supersonic.ui.views.current.whenVisible ->
_refreshViewData() if $scope.dataId
supersonic.ui.views.current.params.onValue (values) ->
$scope.dataId = values.id
_refreshViewData()
$scope.remove = (id) ->
$scope.showSpinner = true
$scope.client.delete().then ->
supersonic.ui.layers.pop()
)
I think you are overloading (in the linguistic sense, not the coding sense) ng-bind. Doing all of that code in your HTML is messy and is not what it was created for. You would be better off doing the math in your controller, and then referencing it in ng-bind. You have only 3 pairs here, but you say you have 20, and could be more, so do it that way:
<span ng-bind="totalPrice"></span>
And in your controller:
var setTotalPrice = function() {
var ret = 0, i, maxClient = 6, client = $scope.client; // or however else you keep track of them
for (i=1;i<=maxClient;i++) {
if (client['q'+i] && client['q'+i].price && !isNaN(client['q'+i].price) &&
client['p'+i] && client['p'+i].price && !isNaN(client['p'+i].price)) {
ret += (client['q'+i].price * client['p'+i].price);
}
}
$scope.totalPrice = ret;
};
$scope.setTotalPrice = setTotalPrice;
setTotalPrice();
Just call setTotalPrice in your controller whenever you want, or on an ng-click.
Please don't abuse ng-bind for calculations! Instead calculate the values in your controller and bind the resulting value.
Problem with your code is -if any of the values is not a number your result becomes NaN. In the controller function you check for the presence of value and then operate. You may want to check whether the value is non-null as well as a number string and then operate on it.