Swift access array with index gives following error. Any idea why? - swift

let index1 = arc4random_uniform(10);
let x = array[index1];
The second line is giving following error
could not find an overload for 'subscript' that accepts the supplied arguments
let x = array[index1];
^~~~~~~~~~~~~

you have to convert the index to Int like e.g. this:
let index1: UInt32 = arc4random_uniform(10); // with the type of the value
let x = array[Int(index1)];
the Int is the proper index type rather than UInt32.
UPDATE
if you are not quiet happy to convert the index every individual time, you can also add an extension to Array with defining a new subscript for your generic index type(s), e.g. such extension would look with UInt32 like this:
extension Array {
subscript (index: UInt32) -> T {
get {
let intIndex : Int = Int(index)
return self[intIndex]
}
}
}
NOTE: I have not worked out the setter here.

Related

Value of type _ cannot convert to specified type Set<> Swift

I'm trying to create a set of random exercises. I have made my struct Hashable and Equatable following the tutorial here https://medium.com/#JoyceMatos/hashable-protocols-in-swift-baf0cabeaebd and that is working fine so it's ready to be put in a Set<>.
When I use an Array to collect the workout exercises, as per below, it works fine. But when I switch to a Set<> I get an error "cannot convert value of type [_] to specified type 'Set'. What is it about 'Sets' that mean you can't map in the same way as an Array?
func generateWorkout() {
let allPossibleExercises = masterExerciseArray
let numberOfExercisesKey = Int(arc4random_uniform(4)+3)
//error triggers on the line below if I switch [WorkoutExercise]
//for Set<WorkoutExercise> (which conforms to Hashable/Equatable
let workoutSet : [WorkoutExercise] = (1...numberOfExercisesKey).map { _ in
let randomKey = Int(arc4random_uniform(UInt32(allPossibleExercises.count)))
return WorkoutExerciseGenerator( name: allPossibleExercises[randomKey].name,
maxReps: allPossibleExercises[randomKey].maxReps).generate()
}
print (workoutSet)
}
There is an answer here with a similar error message Cannot convert value of type '[_]' to specified type 'Array' but my array wouldn't be empty as in this example so I don't think this is the same root cause?
UPDATE : for anyone having the same problem, you can use Array but then simply convert the Array to a Set afterwards if the correct elements are Hashable/Equatable
If creating the array works create the array and then make the Set from the array. If all involved objects conform to Hashable this is supposed to work.
func generateWorkout() {
let allPossibleExercises = masterExerciseArray
let numberOfExercisesKey = Int(arc4random_uniform(4)+3)
let workoutArray : [WorkoutExercise] = (1...numberOfExercisesKey).map { _ in
let randomKey = Int(arc4random_uniform(UInt32(allPossibleExercises.count)))
return WorkoutExerciseGenerator( name: allPossibleExercises[randomKey].name,
maxReps: allPossibleExercises[randomKey].maxReps).generate()
}
let workoutSet = Set(workoutArray)
print (workoutSet)
}

How to solve "Argument type 'CustomStruct' does not conform to expected type 'Sequence'"

I was trying to use the codes below to shuffle an array consisted of a simple custom struct called Card, and I get an error at cards.remove(at: randomIndex):
Error: Argument type 'Card' does not conform to expected type 'Sequence'
Here are the codes:
var cards = [Card]() // declare the array
var shuffledCards = [Card]()
for _ in cards.indices {
let randomIndex = Int(arc4random_uniform(UInt32(cards.count)))
shuffledCards += cards.remove(at: randomIndex) // error appears here
}
cards = shuffledCards
Oddly, as a contrast, the similar design works for Array<String>:
var emojiChoices = ["🦇", "😱", "🙀", "😈", "🎃", "👻", "🍭", "🍬", "🍎"]
let randomIndex = Int(arc4random_uniform(UInt32(emojiChoices.count)))
emoji[card.identifier] = emojiChoices.remove(at: randomIndex)
Should I add something the the definition of Card? If so, what should I add? Thanks!
The += operator in
shuffledCards += cards.remove(at: randomIndex)
expects a sequence of elements which should be append to the
shuffledCards array (for example another array). To append a single element, use
shuffledCards.append(cards.remove(at: randomIndex))

Subscript range of [UInt8] - Swift

So the issue I'm having is that I have an object with a argument in the init() that requires an [UInt8]. I want to be able to grab a range from another array and use that in the init. See example.
class Test {
init(fromArray: [UInt8]) {
// performs work
}
}
let myStockArray: [UInt8] = [1,2,3,4,5,6,7,8] // reference array
let test = Test(fromArray: myStockArray[1...4]) // doesn't work
How can I get this to work? The error I get is: Cannot subscript a value of type '[UInt8]' with an index of type 'CountableClosedRange'
Subscripting an array with a range doesn't return an array and this is the main issue. You are trying to setArraySlice<UInt8> type data to the constructor that have inside [UInt8] type.
Try this approach:
class Test {
init(fromArray: [UInt8]) {
// performs work
}
}
let myStockArray: [UInt8] = [1,2,3,4,5,6,7,8] // reference array
let test = Test(fromArray: Array(myStockArray[1...4]))

Reference to generic type 'Dictionary' requires arguments in <..> [duplicate]

let index1 = arc4random_uniform(10);
let x = array[index1];
The second line is giving following error
could not find an overload for 'subscript' that accepts the supplied arguments
let x = array[index1];
^~~~~~~~~~~~~
you have to convert the index to Int like e.g. this:
let index1: UInt32 = arc4random_uniform(10); // with the type of the value
let x = array[Int(index1)];
the Int is the proper index type rather than UInt32.
UPDATE
if you are not quiet happy to convert the index every individual time, you can also add an extension to Array with defining a new subscript for your generic index type(s), e.g. such extension would look with UInt32 like this:
extension Array {
subscript (index: UInt32) -> T {
get {
let intIndex : Int = Int(index)
return self[intIndex]
}
}
}
NOTE: I have not worked out the setter here.

Optional vs Bound value assigning var from array

I want to check if there is a value in a array and if so assign to a String using a if-left statement:
if let scoreValue = scoreValueArray[element!]{
// do something with scoreValue
}
Error: Bound value in a conditional binding must be of optional type
So tried changing the ! to ? but error persists.
Any input appreciated.
scoreValueArray is an array of strings, where a String value is appended to array if a condition is met, then array is saved to NSUserdefaults.
So element is a int which corresponds to a index in the array, bt only if the index is occupied with a String, so
scoreValueArray[element!]
could return an 'Index out of bounds', hence want to use the if-let.
Although the accepted answer clearly puts why optional binding is not available in the current implementation, it doesn't provide with a solution.
As it is shown in this answer, protocols provide an elegant way of safely checking the bounds of an array. Here's the Swift 2.0 version:
extension Array {
subscript (safe index: Int) -> Element? {
return indices ~= index ? self[index] : nil
}
}
Which you can use like this:
let fruits = ["Apple", "Banana", "Cherry"]
if let fruit = fruits[safe: 4] {
// Do something with the fruit
}
It's not clear what type your scoreValueArray is, but for the sake of this answer, I'm going to assume it's an array of Int.
var scoreValueArray: Array<Int>
Now, if we look the definition of the Array struct, we'll find this:
struct Array<T> : MutableCollectionType, Sliceable {
// other stuff...
subscript (index: Int) -> T
// more stuff
}
So, calling the subscript method on our array (which is what we do when we say scoreValueArray) returns a non-optional. And non-optionals cannot be used in the conditional binding if let/if var statements.
We can duplicate this error message in a more simple example:
let foo: Int = 3
if let bar = foo {
// same error
}
This produces the same error. If we instead do something more like the following, we can avoid the error:
let foo: Int? = 3
if let bar = foo {
// perfectly valid
}
This is different from a dictionary, whose subscript method does return an optional (T?). A dictionary will return a value if the key passed in the subscript is found or nil if there is no value for the passed key.
We must avoid array-index-out-of-bounds exceptions in the same way we always do... by checking the array's length:
if element < scoreValueArray.count {
scoreValue = scoreValueArray[element]
}