Unexpected error in Array append with Swift - arrays

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

Related

How do you properly setup Unsafe Pointers to access CFDictionary Keys and Values?

I am trying to access the keys and values in a CFDictionary which is created from a CGImageSource. Here is the definition of the function used to access Keys and Values data:
func CFDictionaryGetKeysAndValues(_ theDict: CFDictionary!,
_ keys: UnsafeMutablePointer<UnsafeRawPointer?>!,
_ values: UnsafeMutablePointer<UnsafeRawPointer?>!)
My problem is with creating the two pointers for the Keys and Values arrays. Also, I am really unsure whether I am declaring the Arrays the correct way. Here is the description of the CFDictionaryGetKeysAndValues keys and values parameters:
A C array of pointer-sized values that, on return, is filled with keys from the theDict. The keys and values C arrays are parallel to each other (that is, the items at the same indices form a key-value pair from the dictionary). This value must be a valid pointer to a C array of the appropriate type and size (that is, a size equal to the count of theDict), or NULL if the keys are not required. If the keys are Core Foundation objects, ownership follows the The Get Rule.
Here is my implementation according to what I understand of the Unsafe pointers API, but it gives me unreliable results:
// Get the CFDictionary and count the number of returned properties
let imageProperties: CFDictionary = CGImageSourceCopyProperties(imageSource, nil)!
let propCount = CFDictionaryGetCount(imageProperties)
// Create a stub UnsafeRawPointer used to initialize Array
let string: String = ""
let stubPointer = UnsafeRawPointer(string)
// Initialize an Array of pointers for the Keys and one for the Values
var aKeys: Array<UnsafeRawPointer> = Array(repeating: stubPointer, count: propCount)
var aValues: Array<UnsafeRawPointer> = Array(repeating: stubPointer, count: propCount)
// Create the pointers and !hopefully! access dictionary Keys and Values
withUnsafePointer(to: &aKeys[0], {(ptr: UnsafePointer<UnsafeRawPointer>?) -> Void in
var ptrKeysM = UnsafeRawPointer(ptr)
let ptrKeys = UnsafeMutablePointer(&ptrKeysM)!
ptrKeys.initialize(to: ptrKeysM, count: propCount)
withUnsafePointer(to: &aValues[0], {(ptr2: UnsafePointer<UnsafeRawPointer>?) -> Void in
var ptrValuesM = UnsafeRawPointer(ptr2)
let ptrValues = UnsafeMutablePointer(&ptrValuesM)!
ptrValues.initialize(to: ptrValuesM, count: propCount)
CFDictionaryGetKeysAndValues(imageProperties, ptrKeys, ptrValues)
})
})
Now this compiles correctly. When the CGImageSource only returns 1 property, everything goes well (ie: the application doesn't crash). However, if the CGImageSource returns more than 1 property, I get the following error after the call to CFDictionaryGetKeysAndValues:
error: memory read failed for 0x1f600
Thread 1: EXC_BAD_ACCESS (code=1, address=0x1f637)
You might have guessed that I am totally new to Swift and I still have not wrapped my head around this API for pointers. From what I understand, the GetKeysAndValues call returns pointers to the Keys and Values which are stored in the aKeys and aValues Arrays. Is this correct? Thank you all for your help.

Declare an array from Core Data Attribute Swift

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.

converting an element of an array to a separate String

So I have this problem where I can't convert an element of my array to a string
I have a string like this
var description:[String] =["blue","yellow","red"]
and I want to give one element of my array to another variable which is chosen by another integer like this
var pick:[Int] = 2
var chosen:[String] = description[pick]
it says Cannot assign value of type 'String' to type '[String]' and to fix it xcode suggests to do it like this
var chosen:[String] = [description[pick]]
now if I want to cast this variable to another one or give it to a function or whatever it will say Cannot assign value of type 'String' to type '[[String]]' please help.
You are getting very confused here...
First...
var array = ["red", "yellow"]
Is an array of strings. Don't call it description. Call things what they are.
Second...
var pick: [Int]
Is declaring an array. Setting it = 2 doesn't make sense.
Change your last line to...
var chosen: String = array[pick]
In the above line using [String] here is telling the system that you are getting an array of Strings. You're not. You're getting a String here.
Is required for variable chosen to be an array?
Otherwise you could just:
var chosen: String = description[pick]

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 }

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