I have this array:
var currentTouches = [UITouch]()
At any point, it may contain 0-5 UITouches. I want to check each index and do something with the content if it exists.
But I cannot find a way to check without getting an error. The problem seems to be, that UITouch isn't an optional, so I can't just ask if it is nil.
What do I do? I tried making it an optional, but that makes much of my other code unusual. Surely there must be a simple solution.
The valid indices of currentTouches are simply currentTouches.indices. So to check if an index i is valid, you could check if currentTouches.indices.contains(i). You could also check if i < currentTouches.count (assuming you already know that i >= 0).
An easier way of doing that would be to just loop on the valid indices and handle each in turn:
for index in currentTouches.indices {
// handle value at index
}
Or if you don't care about the indices:
for touch in currentTouches {
// handle touch
}
Even better is to use enumerated() which gives you a tuple containing the index and value:
for (index, touch) in currentTouches.enumerated() {
// handle touch at index
}
Related
I know you shouldn't, I kind of know why. But I mean I don't understand my own code once I am trying really to think what's going on.
So I have an array with bunch of objects. I am iterating over it and once I find an object with specific type, I remove it from the array, and add another object into the array. So something like this:
var arr = parent.allchildren() //getting all the children in array
for ele in arr{
if(ele==somethingHere){
parent.remove(ele)
parent.add(new ele) //add new child into child array
}
}
If I have an array of 1,2,3,4,5, and I remove 3 and add a 6 while iterating, the actual array would be 1,2,4,5,6 but the array I am iterating would still be 1,2,3,4,5.
Which I think it would be fine, because at the end I still get what I want, which removed the element and added the element I need. However modifying the list while iterating it is bad and you shouldn't do that, but for my case I think it does what I need. What could be the potential issue in my case that I can't see?
One thing you may want to think about doing is making all of the changes at the end of the iteration. Instead of making the changes one by one, record the changes you want to make while iterating, and then actually make those changes once your loop is finished.
For example, you could make an array of elements to remove, and an array of elements to add.
//Our array where we record what we want to add
var elementsToAdd = [Any]()
//Our array of what elements we want to remove. We record the index at
//which we want to remove the element from the array
var indexesToRemoveAt = [Int]()
//Getting all the children in array
var arr = parent.allchildren()
//Enumerating an array allows us to access the index at which that
//element occurs. For example, the first element's index would be 0,
//the second element's index would be 1, the third would be 2, and so
//on
for (index,ele) in arr.enumerated() {
if(ele == somethingHere) {
indexesToRemoveAt.append(index)
elementsToAdd.append(newEle)
}
}
//Now that we have recorded the changes we want to make, we could make
//all of the changes at once
arr.remove(at: indexesToRemoveAt)
arr.append(contentsOf: elementsToAdd)
Note that removing array elements at multiple indexes would require the following extension to Array. If you wanted to avoid creating this extension, you could always just loop through the array of indexes and tell the array to remove at each individual index. All this extension function is really doing is looping through the indexes, and removing the array element at said index.
Array extension to remove elements at multiple indexes:
extension Array {
//Allows us to remove at multiple indexes instead of just one
mutating func remove(at indexes: [Int]) {
for index in indexes.sorted(by: >) {
if index <= count-1 {
remove(at: index)
}
}
}
}
I just tested in a playground with the following code:
var arr = ["hi", "bye", "guy", "fry", "sky"]
for a in arr {
if arr.count >= 3 {
arr.remove(at: 2)
}
print(a)
}
print(arr)
This prints:
hi
bye
guy
fry
sky
["hi", "bye"]
So it looks like when you use a for-in loop in Swift, the array is copied and changes you make to it will not affect the array you are iterating over. To answer your question, as long as you understand that this is the behavior, there's nothing wrong with doing this.
Reading up on Sets and Arrays I find that a Set cannot, or is not able to store duplicate values ( Ints, Strings, etc ).
Knowing this, if we are to solve for finding a duplicate Int in an array and one method is to convert the Array to a Set, how come we don't get an error once the Array is a Set?
The methods below simply return a Bool value if the array contains duplicates.
import UIKit
func containsDuplicatesDictionary(a: [Int]) -> Bool {
var aDict = [Int : Int]()
for value in a {
if let count = aDict[value] {
aDict[value] = count + 1
return true
} else {
aDict[value] = 1
}
}
return false
}
containsDuplicatesDictionary(a: [1,2,2,4,5])
func containsDuplicatesSet(a: [Int]) -> Bool {
return Set(a).count != a.count
}
containsDuplicatesSet(a: [1,2,2,4])
The first function, containsDuplicatesDictionary, I convert the array to a Dictionary, of course this takes a for loop as well. The Set method can be done in one line, which is really nice. But I guess since I am new to this, I would think converting the array would throw an error immediately since theres duplicate values.
What am I missing when it's converted
Thank you.
Set, by design is an unordered, unique collection of elements. The implementation of Set takes care of duplicate values itself, when you try to add a duplicate value, it checks whether the value is already present in the Set or not and if it is, the value is not added.
When you call the initializer of Set that takes a sequence as its input parameter (this is what you use when writing Set(a), where a is of type [Int], under the hood, the initializer adds the elements one by one checking whether any of the new elements are already present in the Set or not.
You could make a custom initializer method for Set that would throw an error if you would try to add a duplicate value to it, but it wouldn't really have any advantages for any users of Swift, hence the current implementation that just doesn't add the value if it is already present in the Set and doesn't throw an error. This way, you can safely and easily get rid of any duplicates in a non-unique collection of elements (such as an array).
so I am working on a graphical calculator (bit more of a challenge than the basic windows one), and I want to be able to do the entire "math" in one textfield, just like typing in "5+3-5*11/3" and it gives you the solution when you press '='
I decided to make it with arrays of numbers and symbols, but I have no idea how to make it to fill the next array if this one already is used:
var numbers:Array = new Array("","","","","","","","","","","","","","","","");
var actions:Array = new Array("","","","","","","","","","","","","","","","");
I am using split to split the numbers I input with symbols, and I want the numbers to be placed in the arrays. Example: I type in 555+666 and then I need to have something like
if (numbers[0] = "") {numbers[0] = 555}
else if (numbers[1] = "") {numbers[1] = 555}
else if.....
Know what I mean?
Pretty hard to describe...
something like... When I type in a number, if the numbers[0] is already filled, go fill in numbers[1], if numbers[1] is filled, go to numbers[2] etc
Even if I agree with #Nbooo and the Reverse Polish Notation
However Vectors may have a fixed length.
This is not an answer but just an example (if the length of Your Array must be defined):
//Just for information..
var numbs:Vector.<Number> = new Vector.<Number>(10,true);
var count:uint = 1;
for (var i in numbs){
numbs[i] = count++
}
trace(numbs);
// If You try to add an element to a Vector,
// You will get the following Error at compile time :
/*
RangeError: Error #1126: Cannot change the length of a fixed Vector.
at Vector$double/http://adobe.com/AS3/2006/builtin::push()
at Untitled_fla::MainTimeline/frame1()
*/
numbs.push(11);
// Will throw an Error #1126
trace(numbs);
If You use this code to update a fixed Vector, this will not throw an ERROR :
numbs[4]=11;
trace(numbs);
Output :
1,2,3,4,5,6,7,8,9,10
1,2,3,4,11,6,7,8,9,10
// length is 10, so no issue...
If You consider the performance between Arrays and vectors check this reference : Vector class versus Array class
I hope this may be helpful.
[EDIT]
I suggest you to check at those links too :
ActionScript 3 fundamentals: Arrays
ActionScript 3 fundamentals: Associative arrays, maps, and dictionaries
ActionScript 3 fundamentals: Vectors and ByteArrays
[/EDIT]
Best regards.
Nicolas.
What you want to implement is the Reverse Polish Notation. In actionscript3 arrays are dynamic, not fixed size, that means you can add elements to the array without concern about capacity (at least in your case).
const array:Array = new Array();
trace(array.length); // prints 0
array.push(1);
array.push(2);
trace(array.length); // prints 2
I suggest using "push" and "pop" methods of Array/Vector, since it's much more natural for such task. Using those methods will simplify your implementation, since you'll get rid of unnecessary checks like
if (numbers[1] == "") {...}
and replace it just with:
numbers.push(value);
and then to take a value from the top:
const value:String = numbers.pop();
I'm looking for a definitive way to range over a Go map in-order.
Golang spec states the following:
The iteration order over maps is not specified and is not guaranteed to be the same from one iteration to the next. If map entries that have not yet been reached are removed during iteration, the corresponding iteration values will not be produced. If map entries are created during iteration, that entry may be produced during the iteration or may be skipped. The choice may vary for each entry created and from one iteration to the next. If the map is nil, the number of iterations is 0.
All I've found here on StackOverflow and Googling are (imho) workarounds that I don't like.
Is there a solid way to iterate through a map and retrieve items in the order they've been inserted?
The solutions I've found are:
Keep track of keys and values in two separate slices: which sounds like "Do not use a map", losing all the advantages of using maps.
Use a map but keep track of keys in a different slice: this means data duplication which might lead to data misalignment and eventually may bring loads of bugs and painful debugging.
What do you suggest?
Edit in response to the possible duplicate flag.
There's a slight difference between my question and the one provided (this question, but also this one), both questions asked for looping through the map following the keys lexicographic order; I, instead, have specifically asked:
Is there a solid way to iterate through a map and retrieve items in the order they've been inserted?
which is not lexicographic and thus different from #gramme.ninja question:
How can I get the keys to be in order / sort the map so that the keys are in order and the values correspond?
If you need a map and keys in order, those are 2 different things, you need 2 different (data) types to provide that functionality.
With a keys slice
The easiest way to achieve this is to maintain key order in a different slice. Whenever you put a new pair into the map, first check if the key is already in it. If not, add the new key to the separate slice. When you need elements in order, you may use the keys slice. Of course when you remove a pair, you also have to remove it from the slice too.
The keys slice only has to contain the keys (and not the values), so the overhead is little.
Wrap this new functionality (map+keys slice) into a new type and provide methods for it, and hide the map and slice. Then data misalignment cannot occur.
Example implementation:
type Key int // Key type
type Value int // Value type
type Map struct {
m map[Key]Value
keys []Key
}
func New() *Map {
return &Map{m: make(map[Key]Value)}
}
func (m *Map) Set(k Key, v Value) {
if _, ok := m.m[k]; !ok {
m.keys = append(m.keys, k)
}
m.m[k] = v
}
func (m *Map) Range() {
for _, k := range m.keys {
fmt.Println(m.m[k])
}
}
Using it:
m := New()
m.Set(1, 11)
m.Set(2, 22)
m.Range()
Try it on the Go Playground.
With a value-wrapper implementing a linked-list
Another approach would be to wrap the values, and –along the real value– also store the next/previous key.
For example, assuming you want a map like map[Key]Value:
type valueWrapper struct {
value Value
next *Key // Next key
}
Whenever you add a pair to the map, you set a valueWrapper as the value, and you have to link this to the previous (last) pair. To link, you have to set next field of the last wrapper to point to this new key. To easily implement this, it's recommended to also store the last key (to avoid having to search for it).
When you want to iterate over the elements in insertion order, you start from the first (you have to store this), and its associated valueWrapper will tell you the next key (in insertion order).
Example implementation:
type Key int // Key type
type Value int // Value type
type valueWrapper struct {
v Value
next *Key
}
type Map struct {
m map[Key]valueWrapper
first, last *Key
}
func New() *Map {
return &Map{m: make(map[Key]valueWrapper)}
}
func (m *Map) Set(k Key, v Value) {
if _, ok := m.m[k]; !ok && m.last != nil {
w2 := m.m[*m.last]
m.m[*m.last] = valueWrapper{w2.v, &k}
}
w := valueWrapper{v: v}
m.m[k] = w
if m.first == nil {
m.first = &k
}
m.last = &k
}
func (m *Map) Range() {
for k := m.first; k != nil; {
w := m.m[*k]
fmt.Println(w.v)
k = w.next
}
}
Using it is the same. Try it on the Go Playground.
Notes: You may vary a couple of things to your liking:
You may declare the internal map like m map[Key]*valueWrapper and so in Set() you can change the next field without having to assign a new valueWrapper.
You may choose first and last fields to be of type *valueWrapper
You may choose next to be of type *valueWrapper
Comparison
The approach with an additional slice is easier and cleaner. But removing an element from it may become slow if the map grows big, as we also have to find the key in the slice which is "unsorted", so it's O(n) complexity.
The approach with linked-list in value-wrapper can easily be extended to support fast element removal even if the map is big, if you also add the prev field to the valueWrapper struct. So if you need to remove an element, you can super-fast find the wrapper (O(1)), update the prev and next wrappers (to point to each other), and perform a simple delete() operation, it's O(1).
Note that deletion in the first solution (with slice) could still be sped up by using 1 additional map, which would map from key to index of the key in the slice (map[Key]int), so delete operation could still be implemented in O(1), in exchange for greater complexity. Another option for speeding up could be to change the value in the map to be a wrapper, which could hold the actual value and the index of the key in the slice.
See related question: Why can't Go iterate maps in insertion order?
I have a set of Strings, which I split it out and save it into an Array, and try to loop it with api as a parameter, but it keep crash with error
index out of range
why is it? Need help pls
You should learn about array basic ideas. This error shows becuse the item you request is not available in the array.
for i in 0...qrCoderArrau.count - 1 {
}
The error is because you are trying to access an element in array with an index greater than its size - 1.
Your qrCodeArray Array is empty also you need to for loop less one to the count of qrCodeArray. So change you for loop like this.
for i in 0..<qrCodeArray.count {
}
In your case for i in 0...qrCoderArray.count { it will execute for loop if your qrCoderArray.count is 0.
To avoid those errors (the last index of an array is count-1) use always
for qrCode in qrCodeArray { ...
rather than an index loop and even if you need the index use
for (index, qrCode) in qrCodeArray.enumerate() { ...
I think best solution is foreach in these situations
for qr in qrCoderArray {
...
}