Declare an array from Core Data Attribute Swift - arrays

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.

Related

How do I retrieve an item from an array that is inside a dictionary?

I'm trying to create a dictionary that has an array as the value of one of the dictionary items in Swift. I want to be able to retrieve a certain element in the array, but when I try to do it I get an error.
Here's my code:
var country = ["USA": [37.0902, 95.7129]]
let countrylatitude = country["USA"]
print(countrylatitude[0])
The error message was: Value of optional type '[Double]?' must be unwrapped to refer to member 'subscript' of wrapped base type '[Double]'
What does this mean? Thanks!
Unwrapped basically means to check and make sure the value exists. countrylatitude possibly could be equal to nil because it doesn't know if "USA" is part of the dictionary.
There are multiple ways to unwrap to make sure it exists...
Force unwrap will crash if it is equal to nil
countrylatitude![0]
if let will only run if it can define a constant that is not equal to nil
if let latitude = countrylatitude {
print(latitude[0])
}
guard let will not run any code after the guard statement unless it is not equal to nil
guard let latitude = countrylatitude else { return }
print(latitude[0])
Keep in mind that if the index of latitude[0] is not automatically assigned optional so if when you do countrylatitude[0] it is essentially just force unwrapping the index and it will crash if that index [0] does not exist.

How to add an array elements in swift?

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

Is it possible to define the length of a list in F#?

For example, I define a record as:
type a = {b : float; c: int list}
but I already know that this list must be of a predefined size, let's say 2 and if the list is not 2 it would be a different type or error since it is not defined such a type.
Is it possible to define the size of the list as happens in other languages that you must define the size?
Depending on the application this question can be applied to an array.
Maybe you should use an array instead of a list, since an array has a fixed length:
// create an array of length = 2, initialized with zeros.
let cValues : int[] = Array.create 2 0
cValues.IsFixedSize // returns true
EDIT: As others have suggested, a tuple might also be the way to go. For a pair (a tuple of length two), you can access the values using the fst and snd functions.
For a longer tuple, you can use pattern matching as shown below. If the tuple is too long to make this pattern matching approach practical, then you probably need a structure other than an F# tuple. Of course, one major requirement to consider is whether you need to store values of mixed types. A tuple or a record can store a mix of multiple types, whereas an array or list stores values of a single type.
let fourTuple = (5, 10, 2, 3)
let _,_,third,_ = fourTuple
printfn "%d" third // displays "2"
If an array or a tuple won't meet your requirements, then maybe you should use another record like this:
type ListOfC = {c1 : int; c2 : int}
type a' = {b' : float; c' : ListOfC}
Or you could create a new class that would meet your requirements, starting like the script below. Of course, this would probably not be considered idiomatic functional programming style. It's more like OOP.
type ListOfTwo(firstInt : int, secondInt : int) =
member this.First = firstInt
member this.Second = secondInt
let myListOfTwo = ListOfTwo(4, 5)
myListOfTwo.First
type a = {b : float; c : ListOfTwo }

Unexpected error in Array append with Swift

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))

Creating an Array2D in F# (VS2010 Beta 1)

Consider the following code fragment in VS2010 Beta 1:
let array = Array2D.zeroCreate 1000 500
This produces an error, namely:
error FS0030: Value restriction. The value 'array' has been inferred to have
generic type val array : '_a [,]
Either define 'array' as a simple data term, make it a function with explicit
arguments or, if you do not intend for it to be generic, add a type annotation.
Can I explicitly set the type (in my case a grid of string)?
You can explicitly specify the type like this:
let array : string [,] = Array2D.zeroCreate 1000 500
For further information on the value restriction you might want to take a look at this F#-Wiki page.
You can also use init to create an array though it might be slower.
let array = Array2D.init 1000 500 (fun _ _ -> "")
Zeroing out an array is usually not seen in functional programming. It's much more common to pass an initilization function to init and just create the array with the values you want.
To create a 2-dimensional array containing empty strings:
let array = Array2D.create 1000 500 ""

Resources