I am working with arrays this time and I want to add elements. Whenever a user adds some value in the array I want it to be added to the previous value and give me the total value.
struct KeyValues{
var category:String!
var amount:String!
}
var arrExpense = [KeyValues]()
In my case, I am adding values to the amount variable. I want the sum of all the values user has added to the amount values. How can I achieve that in swift. Do I need to use loop or something else?
First of all never declare a struct member as implicit unwrapped optional. If it's supposed to be optional declare it as regular optional (?)
Second of all if a value won't change (maybe category) declare it as constant (let)
You can sum up the values with compactMap and reduce
struct KeyValues {
let category : String
var amount : String
}
let sum = arrExpense.compactMap{Int($0.amount)}.reduce(0, +)
compactMap is necessary to filter the strings which cannot be converted to Int. Consider to use a numeric type for amount
see this switf arrays article
let numbers = [1,2,3,5]
numbers.append(6) // [1,2,3,5,6]
numbers.insert(4, at: 3) // [1,2,3,4,5,6]
numbers.remove(at: 1) // [1,3,4,5,6]
numbers.removeLast() // [1,3,4,5]
let total = numbers.reduce(0, +) // 0 = starting point, + = operation
// 0 + 1 + 3 + 4 + 5 = 13
Related
I have array contain string items in scala , each item contain from prefix + || + double value like below :
var y = Array("Zara||6.0", "Nuha||4.0","Zara||2.0","Zara||0.1")
what I want to Do :
i need sum all double value from above array (y(i).split("\|\|")(1)) But if the prefix the duplicated in the array then I only want sum the max value like below :
for item Zara we have 3 values i want to take the max (in our sample it 6.0)
for item Nuha it unique then i will take it's value (4.0)
the excepted output is (6.0+4.0)=10.0
is there are any way to do it in scala rather than using 2 instead loop ?
Prepare your array: extract prefix and values into tuple. Use foldLeft for aggregate max elem for each prefix, and sum values
val res = y.map(_.split("\\|\\|")).map(arr => (arr(0), arr(1).toDouble))
.foldLeft(Map.empty[String, Double]) { (acc, elem) =>
val value = acc.get(elem._1).map(math.max(_, elem._2)).getOrElse(elem._2)
acc + (elem._1 -> value)
}.values.sum
println(res)
You can do it pretty much in one step (it's three steps technically, but only one specifically addressing your requirement, everything else (split and sum) is kinda a given either way.
y
.iterator
.map(_.split("""\|\|"""))
.groupMapReduce(_.head)(_.last.toDouble)(_ max _)
.values
.sum
Also ... do not use vars. Even if you just putting together a quick sample. Vars are evil, just pretend they do not exist at all ... at least for a while, until you acquire enough of a command of the language to be able to tell the 1% of situations, where you might actually need them. Actually, avoid using Arrays as much as possible too.
I have an Entity named: Transaction and an Attribute named: amount.
I would like to declare an array from amount attribute that can using the summing an array sample code
sum = array_name.reduce(0,+)
I am trying to do this way to declare an array from Attribute
var amountArray =
(self.transactionsArray as NSArray).value(forKey: "amount") as! NSArray
sum = amountArray.reduce(0,+)
but it's not working and throw the error
Ambiguous reference to member '+'
Using Swift 4, #MartinR's suggestion should work. If it doesn't, you should provide more information about your code, maybe specifically about the details of Transaction, the type of the amount variable, and about the exact nature of transactionsArray.
Assuming that transactionsArray is declared as the non-optional [Transaction] and that amount is one of the Core Data numeric types,
let sum = transactionsArray.reduce(0) { $0 + $1.amount }
...is correct. You might make it slightly more explicit by declaring the type of sum:
let sum : Double = transactionsArray.reduce(0) { $0 + $1.amount }
(Make sure to use the same type as amount here, I'm just guessing Double).
It's possible to get the sum with an NSArray and the #sum operator, for example
if let sum = (transactionsArray as NSArray).value(forKeyPath:"#sum.amount") as? Double {
....
}
The as? Double is needed because of the lack of type info on NSArray that #vadian mentioned.
var playerOneArray : Array<(Int,Int,Int)> = []
var currentPerson = 1
var currentWeapon = 1
var currentRoom = 1
var currentPlayer = 1
currentPerson = everyPicker.selectedRowInComponent(0)
currentWeapon = everyPicker.selectedRowInComponent(1)
currentRoom = everyPicker.selectedRowInComponent(2)
currentPlayer = playerPicker.selectedRowInComponent(0)
//In an if statement
playerOneArray.append(currentRoom, currentPerson, currentWeapon) as (Int,Int,Int)
// Error tuple types () and (Int,Int,Int) have a different number of elements (0 vs. 3)
even if i take away the as int,int,int there is still an error and i don't know why this is happening. the error that comes up if i take it away is accessing members of protocol 'int' is unimplemented.
You are not closing the parenthesis of the append call.
However, because swift knows playerOneArray is an array of 3 Ints. You can simply pass the append method the 3 variables as follows:
playerOneArray.append(currentRoom, currentPerson, currentWeapon)
Assuming (currentRoom, currentPerson, currentWeapon) is a tuple of Int values. This will store (currentRoom, currentPerson, currentWeapon) into playerOneArray[0].
As a side note, it seems you are wanting an array of players which holds each players details. If this is the case you should rename the playerOneArray to players and simply add each player's information. That way each index will represent the players information (the tuple of Ints).
You've got the right idea but your syntax is incorrect.
The way it's written, Swift is looking for a method with the signature:
func append(Int, Int, Int) -> (Int, Int, Int)
That is, a function named append that takes three Ints and returns a tuple of three Ints. The error you're getting is probably because Swift sees the definition append(T) -> () and is complaining that you return 3 components rather than zero.
You could try to just pass a tuple by adding parenthesis but this would fail because Swift treats a single tuple as a list of parameters so it looks for a signature append(Int, Int, Int) -> () which does not exist:
playerOneArray.append((currentRoom, currentPerson, currentWeapon)) // Missing argument for parameter #2 in call.
The correct solution looks very close to what you were doing (maybe you were hinted in that direction):
playerOneArray.append((currentRoom, currentPerson, currentWeapon) as (Int,Int,Int))
This tells Swift that you mean that tuple to really be a tuple and it successfully finds the signature: append((Int, Int, Int)) -> ().
As a side note, tuples are intended for transferring data more so than storing it. If you expect this data to persist long term you should put it in a struct:
struct Player {
var person:Int
var weapon:Int
var room:Int
}
var playerOneArray:[Player] = []
let player = Player(
person: everyPicker.selectedRowInComponent(0),
weapon: everyPicker.selectedRowInComponent(1),
room: everyPicker.selectedRowInComponent(2))
playerOneArray.append(player)
append is getting three parameters instead of one tuple. Try this:
playerOneArray.append((currentRoom, currentPerson, currentWeapon))
var selPage2 = $scope.selPage + $scope.itemsPerPage;
$scope.selPageUp = selPage2;
for example if value of selPage is 50 and value of itemsPerPage is 10 and I want to display my value in HTML element like
{{selPageUp}}
Angular JS will make connection of this two strings and will display it like 5010, but I want to sum up two values to display number 60. How to do that? Example if I change operator from + to * it will multiply value and display 500 it will work on way I want. Help please?
If they are integers:
var selPage2 = parseInt($scope.selPage) + parseInt($scope.itemsPerPage);
Otherwise:
var selPage2 = parseFloat($scope.selPage) + parseFloat($scope.itemsPerPage);
The $scope.selpage and $scope.itemPerPage are probably of type String. if they would be Integers it would sum up fine. so first you have to convert this string to an Integer of Float with parseInt() or parseFloat(). 2 Strings do multiply because * is a Math function so it will automatically TRY to convert these strings in values.
I have an array within an array and I am trying to name the variables using a for loop as there are a lot of variables. When I use the following simple code Time1 = dataCOMB{1,1}{1,1}(1:1024, 1); it opens the first cell in an array and proceeds to open the first cell in the following array and finally defines all the values in column 1 rows 1 to 1024 as Time1. However I have 38 of these different sets of data and when I apply the following code:
for t = 1:38
for aa = 1:38
Time(t) = dataCOMB{1,1}{1,aa}(1:1024, 1);
end
end
I get an error
In an assignment A(I) = B, the number of elements in B and I must be the same.
Error in Load_Files_working (line 39)
Time(t) = dataCOMB{1,1}{1,aa}(1:1024, 1);
Basically I am trying to get matlab to call the first column in each data set Time1, Time2, etc.
The problem:
1)You'd want to extract in a cell row...
2) ...the first 1024 numbers in the 1st column...
3) ...from each of the first 38 cells of a cell array.
The plan:
1) If one wants to get info from each element of a cell array (that is, an array accessed via {} indexing), one may use cellfun. Calling cellfun(some_function, a_cell_array) will aggregate the results of some_function(a_cell_array{k}) for all possible k subscripts. If the results are heterogeneous (i.e. not having the same type and size), one may use the cell_fun(..., 'UniformOutput', false) option to put them in an output cell array (cell arrays are good at grouping together heterogeneous data).
2) To extract the first 1024 numbers from the first column of an numeric array x one may use this anonymous function: #(x) x(1:1024,1). The x argument will com from each element of a cell array, and our anonymous function will play the role of some_function in the step above.
3) Now we need to specify a_cell_array, i.e. the cell array that contains the first 38 cells of the target. That would be, simply dataCOMB{1,1}(1,1:38).
The solution:
This one-liner implements the plan:
Time = cellfun(#(x) x(1:1024,1), dataCOMB{1,1}(1,1:38), 'UniformOutput', false);
Then you can access your data as in this example:
this_time = Time{3};
Your error is with Time(t). That's not how you create a new variable in matlab. To do exactly what you want (ie, create variables names Time1, Time2, etc...you'll need to use the eval function:
for aa = 1:38
eval(['Time' num2str(aa) '= dataCOMB{1,1}{1,aa}(1:1024,1);']);
end
Many people do not like recommending the eval function. Others wouldn't recommend moving all of your data out of a data structure and into their own independently-named variables. So, to address these two criticisms, a better alternative might be to pull your data out of your complicated data structure and to put it into a simpler array:
Time_Array = zeros(1024,38);
for aa = 1:38
Time_Array(:,aa) = dataCOMB{1,1}{1,aa}(1:1024,1);
end
Or, if you don't like that because you really like the names Time1, Time2, etc, you could create them as fields to a data structure:
Time_Data = [];
for aa = 1:38
fieldname = ['Time' num2str(aa)];
Time_Data.(fieldname) = dataCOMB{1,1}{1,aa}(1:1024,1);
end
And, in response to a comment below by the original post, this method can be extended to further unpack the data:
Time_Data = [];
count = 0;
for z = 1:2;
for aa = 1:38
count = count+1;
fieldname = ['Time' num2str(count)];
Time_Data.(fieldname) = dataCOMB{1,z}{1,aa}(1:1024,1);
end
end