Why can a Swift constant be used as a loop index? - swift

I know this Swift code is valid:
let index = 0
for index in (1...9) {
print(index) // index changes value from 1 to 9
}
But then if you say
index += index
you get the error
"Cannot assign to value: 'index' is a 'let' constant"
So, if index is a constant why is it ok to use it in the loop where its value will change?

So, if index is a constant why is it ok to use it in the loop where its value will change?
You could think of index as being newly created and initialized each time through the loop, just as a variable declared inside the loop's body would be. It makes sense to use let here because normally you don't change the loop counter inside the loop.
Update: After the edit, the code makes more sense, and pkamb's comment really is more clear: the index that you declare with let index = 0 is a different variable from the index used in the for loop.

Related

Swift: For Loop End Condition Evaluated Only Once?

I am attempting to understand how Swift handles for-in loops.
Overview: we are iterating over the rows of an NSOutlineView. If a condition is met, we expand the item, which obviously changes the overall row count of the outlineView.
Pre-Condition: the OutlineView has 5 "root" items. Each of those has 5 child items.
Example
final class anOutlineView: NSOutlineView
{
override func reloadData()
{
super.reloadData()
for i in 0 ..< self.numberOfRows
{
// Assume we expand the item at row 0, which increases
// the overall outlineView row count from 5 to 10.
}
}
}
In this approach, the loop stops when i == 4. I assume that's because Swift evaluates the range only once, the first time it encounters it? Is there a way to change that behavior so that the conditions are re-evaluated each time through the loop, like a traditional for loop?
Replacing the for loop with a while loop obviously works and is a fine solution. I'm simply trying to understand the nuances of Swift because this behavior is not what I expected. In Objective-C, the for loop conditions were evaluated on each iteration and it was a well-known performance optimization to refrain from calling self.property in loop conditions (unless a good reason existed, as it does in this case.)
0 ..< self.numberOfRows is a Range and in particular a Sequence. Iterating over a sequence is done by creating an iterator, and then calling its next() method until the iterator is exhausted, compare IteratorProtocol:
Whenever you use a for-in loop with an array, set, or any other collection or sequence, you’re using that type’s iterator. Swift uses a sequence’s or collection’s iterator internally to enable the for-in loop language construct.
So
for i in 0 ..< self.numberOfRows {
...
}
is equivalent to
let range = 0 ..< self.numberOfRows
var it = range.makeIterator()
while let i = it.next() {
...
}
Modifying numberOfRows during the iteration does not mutate the range (which is a value type) or the iterator, and therefore does not affect the number of iterations.

Swift: Get max value for key in array of dictionaries

I have an array containing dictionaries.
let arr = [["test":1], ["test":2], ["test":3], ["test":4]]
I now need to get the one dictionary that contains the highest value for the key "test" (without iterating through everything). I was thinking about filter(_:) but this will only filter out. map(_:) also does not work as I need to filter and not to map.
There's an example how to get the key with the highest value in a dictionary but this does not work in this case.
let hues = ["Heliotrope": 296, "Coral": 16, "Aquamarine": 156]
let greatestHue = hues.max { a, b in a.value < b.value }
print(greatestHue)
Any help is appreciated!
You can use max much like in your example.
let arr = [["test":1], ["test":4], ["test":3], ["test":2]]
print(arr.max { $0["test"]! < $1["test"]! })
This gives the dictionary with the highest value.
Of course the use of ! is bad unless it is guaranteed that each dictionary really has a "text" key.
Also note that using max will still result in the entire array being iterated. You can't avoid that unless your dictionaries are always sorted by the value. Then in that case simply use last instead of max.

'initializeMemory(as:at:count:to:)' is deprecated

As is, I'm using the following code to set a value at an index of a UnsafeMutableRawPointer (the pointer points to an array):
ptr.initializeMemory(as: Float.self, at: idx, count: 1, to: someValue)
This works and sets ptr at idx to someValue. But Xcode is giving me a warning saying that said method is deprecated, and suggesting me to use initializeMemory(as:repeating:count:) instead. However, such method doesn't have an index parameter.
So, my question is: which function should I use in order to appropriately set the value of an UnstableMutableRawPointer at some index?

Assigning times to events

include "globals.mzn";
%Data
time_ID = [11,12,13,14,15];
eventId = [0011, 0012, 0013, 0021, 0022, 0031, 0041, 0051, 0061, 0071];
int:ntime = 5;
int:nevent = 10;
set of int: events =1..nevent;
set of int: time = 1..ntime;
array[1..nevent] of int:eventId;
array[1..nevent] of var time:event_time;
array[1..ntime] of int:time_ID;
solve satisfy;
constraint
forall(event in eventId)(
exists(t in time_ID)(
event_time[event] = t ));
output[ show(event_time) ];
I'm trying to assign times to an event using the code above.
But rather than randomly assign times to the events, it returns an error " array access out of bounds"
How can I make it select randomly from the time array?
Thank you
The error was because you tried to assign the index 11 (the first element in eventId array) in "event_time" array.
The assigment of just 1's is correct since you haven't done any other constraints on the "event_time" array. If you set the number of solutions to - say - 3 you will see other solutions. And, in fact, the constraint as it stand now is not really meaningful since it just ensures that there is some assignment to the elements in "event_time", but this constraint is handled by the domain of "event_time" (i.e. that all indices are in the range 1..ntime).

Fatal Error: Array Index out of range in Swift Xcode6

I keep getting this error in my func
I'm trying to read the value in array answerRecord. I uses a global var arrayCount, which keep track which index im currently pointing to.
func buttonColourControl(){
switch answerRecord[arrayCount]{
case1: xxxxxxx
I did a println in my earlier func and it return a value of int 1 for the var arrayCount
Therefore arrayCount is not empty. So it should be able to interpret the array as:
*assuming arrayCount is now 1
answerRecord[arrayCount] should be interpreted as answerRecord[1]
Please correct me if im wrong
#IBAction func nextButtonClicked(sender: UIButton) {
arrayCount = ++arrayCount
question.text = spouseQuesion[arrayCount]
controlBackNextButton()
answer1Label.text = spouseAnswer1[arrayCount]
answer2Label.text = spouseAnswer2[arrayCount]
answer3Label.text = spouseAnswer3[arrayCount]
println(arrayCount)
buttonColourControl()
}
Let's say you have an array with one object in it:
let arr = ["hello"]
The only valid index into that array is 0. arr[0] is legal. arr[1] is not. The array has 1 element but its index number is 0.
This is true for any array. Every array holds some number of elements. It might be 0 elements, in which case no index is legal. It might be 3 elements, in which case you can refer to the array's elements by index numbers 0, 1, and 2. And so on. That's all. Those are the rules. You cannot use any other index number or you will crash.
So the error message is simply telling you that you are making that mistake. You have an array answerRecord and it has some number of elements - I have no idea how many, and it doesn't matter. Then you are using the expression answerRecord[arrayCount] and the value of arrayCount is outside the bounds I have just explained. That's all you need to know. The error message tells you the bug in your program. Now you can fix it.