iterating though two arrays to output values - ios

So I have two arrays a name array and a values array they are a string and double respectively. I want to be able for a user to type in a textfield and to iterate though the name array until there is a match then output the value that has the same number as the name to be outputted
this is the code i have:
for(var i = 0; i<name.count; i++){
if name[i] == typeFood{
yieldOutput == percent[i]
}
}

First, use find to locate the location of the value in the name array, then use the returned index to look up the percent:
if let idx = find(name, typeFood) {
yieldOutput = percent[idx]
}
You can also combine the two actions together with map to declare an output variable using let:
if let foodPercentage = find(name, typeFood).map({ percent[$0] }) {
// foodPercentage will have a value here
}
else {
// not-found logic here
}

Related

find the minimum index of a repeating element in the array Swift

I dont know how doint that. I try find replacement obj method
indexOfObject on the swift but not find
i have array = [1,3,6,2,3] and input in array value 3, i am need find repeating value with min index from array. Answer with index 1. How do it?
You have to loop through the entire collection, for each item, see if we had seen this before. And as we are doing that, let’s keep track of the index of the first item that has been repeated somewhere in the collection, to see if this is the first repeated item or not:
extension Collection where Element: Hashable {
func indexOfFirstRepeated() -> Index? {
var result: Index? // the index of the first item repeated anywhere else in the collection
var firstOccurrences: [Element: Index] = [:] // dictionary to keep track of the first item that every element was first encountered in the collection
for (index, element) in zip(indices, self) {
if let firstOccurrence = firstOccurrences[element] { // find previous occurrence of this value, if any
if let previousLowestIndex = result { // if we found this element before, let's see if we had already found another repeated element
if firstOccurrence < previousLowestIndex { // if so, let’s see if the first occurrence of this element occurred before the first occurrence of the previously discovered repeated element
result = firstOccurrence
}
} else { // otherwise, no prior repeated element found, so this is our first repeated element found thus far
result = firstOccurrence
}
} else {
firstOccurrences[element] = index // if we got here, this is the first time we've seen this element, so record the index of this first occurrence
}
}
return result
}
}
Thus:
let array = [9,8,7,1,3,6,2,3,1]
if let index = array.indexOfFirstRepeated() {
print(index) // 3
}
Now, obviously, as we iterate through this array, the value 3 is the first value that we will see repeated, but that doesn’t matter, because the repeated value 1 will be found at the very end of the array, and 1’s first index is lower than 3’s first index.
Two observations on the above:
I made it generic, so that it works on any hashable type, e.g.:
let array = ["bill", "sam", "susan", "sam", "bill"]
if let index = array.indexOfFirstRepeated() {
print(index)
} else {
print("not found")
}
I made this a Collection extension (rather than an Array extension) so that it would work on other collection types (e.g. array slices, etc.). You can make it an Array extension, just as easily, but we prefer to use the most abstract type that is convenient, to make it as flexible as possible.
This is basically a riff on uniqued.
import Algorithms
public extension BidirectionalCollection where Element: Hashable {
var firstDuplicate: (index: Index, element: Element)? {
var set: Set<Element> = []
return indexed().reversed().reduce(into: nil) {
if !set.insert($1.element).inserted {
$0 = $1
}
}
}
}
You can get the last duplicate by not reversing before reducing.
Assume you have an array of n integers, with a[i] = i, except that a[1] = a[2] = 1, and I may or may not have have changed a[i] = 0 for some i >= 2.
The smallest index of a duplicate element is either 0 or 1. To find out which you have to find the i >= 2 with a[i] = 0 or find that no such i exists. So you have to visit all array elements.

How to sort the data in in a twoDimensional array alphabetically?

I am currently having a big issue sorting my Data alphabetically in a 2D array. I'm going to try to give you every detail to be as clear as possible.
Currently, I am fetching my contacts with the CNContactStore. This all works fine. I am able to retrieve all the data I want out of my contacts.
Now, I created the following struct:
struct FavoritableContact {
let contact: CNContact
var hasFavorited: Bool
}
With this, I declared and initialized the following array:
var favoritableContacts = [FavoritableContact]()
Once I retrieved my contacts, I simply appended them to favoritableContacts;
try store.enumerateContacts(with: request, usingBlock: { (contact, stopPointerIfYouWantToStopEnumerating) in
favoritableContacts.append(FavoritableContact(contact: contact, hasFavorited: false))
})
To sort them in alphabetical order in the same array, I simply did the following:
var sortedContacts = favoritableContacts.sorted { $0.contact.familyName < $1.contact.familyName }
Now if possible, I want to create the following 2D array,
var 2D = [
[FavoritableContact] //"A"
[FavoritableContact], //"B"
[FavoritableContact], //"C"
[FavoritableContact], //"D"
...
]
I am just not sure how to take my sortedContacts array and separate alphabetically.
I am very new here, If I forgot something, or I didn't do somethign right please let me know.
As was pointed out in the comments, a dictionary with first letters as keys is probably the better way to go as it is much easier to access, though perhaps you have a reason for wanting to use a 2d array instead. To achieve that you could do something like this:
//Create an empty array filled with 26 arrays of FavorableContact
var array2d = Array<[FavoritableContact]>(repeating: [FavoritableContact](), count: 26)
//Find the ascii value for "A" to use as your base
let aAscii = Int("A".unicodeScalars.filter({ $0.isASCII }).map({ $0.value })[0]) //This returns 65, btw, so you could also just hardcode
//Go through your original array, find the first letter of each contact, and append to the correct array
favoritableContacts.forEach { (contact) in
//Get the ascii value for the first letter
let firstLetter = Int(contact.contact.familyName.prefix(1).uppercased().unicodeScalars.filter({ $0.isASCII }).map({ $0.value })[0])
//Append to the array for this letter by subtracting the ascii value for "A" from the ascii value for the uppercased version of this letter.
array2d[firstLetter - aAscii].append(contact)
}
This is not the cleanest thing in the world, and it assumes standard English language alphabet with no diacritics, symbols, numbers or anything else. Assuming that is true it gets the job done.
Could use something like this.
var contactsLeftToSort : [FavoritableContact] = []
var doubleArray : [[FavoritableContact]?] = [[FavoritableContact]?]()
var index : Int = 0
for char in "ABCDEFGHIJKLMNOPQRSTUV" {
doubleArray.append(nil)
var i = 0
while i < contactsLeftToSort.count {
let contact = contactsLeftToSort[i]
if contact.name.first == char {
doubleArray[index] == nil ? doubleArray[index] = [contact] : doubleArray[index]!.append(contact)
contactsLeftToSort.remove(at: i)
}
//assuming original list is alphabetized.. if not, delete this line.
if contact.name.first! > char { break }
i += 1
}
index += 1
}
As I wrote in the comments above, I think you can achieve this in a much more elegant way by using a dictionary instead of an array.
SWIFT 4
let sortedContacts: [FavoritableContact] = ... // An array of FavoritableContact objects, they should be sorted
let groupedContacts = Dictionary(grouping: contacts, by { $0.familyName.first! })
You now have a dictionary of all your contacts where the keys are the alphabetical letters (ie. A-Z) and the values are arrays of sorted FavoritableContact objects (assuming you sorted the big array of FavoritableContacts before creating the dictionary).
If you wanted to use this as the datasource for your tableview, you would make the number of sections all the possible first letters of family names. For the number of rows in each section, you return the count of the array for the key like so:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
let letterForSection = letterForSection() // Custom method to get the section of the letter
return contactsDict[letterForSection].count
}
The rest of the datasource methods would work in a similar way.
Man, all of these answers are really over-complicating this. All you need is something along the lines of:
let groupedContacts = Dictionary(grouping: contacts, by: { $0.contact.firstName.first! })
for initial, contacts in groupedContacts.lazy.sorted().{ $0.key < $1.key} {
print("#################", initial)
contacts.forEach{ print($0) }
}

optional variable names in array - need to create an instance

I'm working with a framework and have to change some things for my project.
The original is
var tree:FBQuadTree? = nil
...
if tree == nil {
tree = FBQuadTree()
}
I need always a custom number of trees. So my consideration was that I use an array for this.
var tree:[FBQuadTree?] = []
...
if tree[number] == nil {
tree[number] = FBQuadTree()
}
But I don't know how to fill my new tree array. Sure I could do smth. like this:
let element:FBQuadTree?
layersTree.append(element)
Okay, but my problem is that number of elements isn't static. So sometimes there is just one element, sometimes a lot more.
Is that possible what I want to do?
the whole thing:
var array:[FBQuadTree] = []
//fill
for i in 0..<MyDynamicSize {
array.append(//how to fill?)
}
//give new values
for i in 0..<MyDynamicSize {
array[i] = FBQuadTree()
}
If you're just trying to get an Array of a myDynamicSize* number of FBQuadTree instances, you can use init(repeating:count:).
var array = [FBQuadTree](count: myDynamicSize, repeatedValue: FBQuadTree())
Sidenote: by convention, types start with capitals, whereas variable names start with lowercase letters. So myDynamicSize, rather than MyDynamicSize
please try this
var array:[FBQuadTree?] = []
//fill
for i in 0..<MyDynamicSize {
array.append(nil)
}

Random number generator function that doesn't repeat itself

Does swift by default has a random number generator that returns the same number only once?
For example it picks a number in range 1,2,3,4,5. Return that random number (lets say 3). In the next loop, it picks only from 1,2,4,5 and so on.
EDIT:
This is what I ended up using. It returns an array of integers from 0-5 and was tested in playground. Note that this is meant to be used when you are picking from a large set of Integers and not just 6.
func generateRandomArray() -> [Int]{
var randomImages: [Int] = [Int]()
var newRandomNumber = Int(arc4random_uniform(UInt32(6)))
while (randomImages.count < 6) {
if (randomImages.contains(newRandomNumber) == false){
randomImages.append(newRandomNumber)
}
newRandomNumber = Int(arc4random_uniform(UInt32(6)))
}
return randomImages
}
This kind of generator is not called a "random number" generator, but usually
a "Shuffle" or "Permute".
You have to tell it how many items there are first. Otherwise what you are proposing doesn't make any sense!
see answer here: How do I shuffle an array in Swift?
You can do this trick, Add the range of numbers from which you want to get the random result..to an NSMutableArray or NSMutableSet(to make sure there is only 1 of it).
Iterate through the array-
for(int i=0;i<myMutableArray .count;i++){
int randomIndex = arc4random_uniform(myMutableArray.count);
int myNumber = [[myMutableArray objectAtIndex:randomIndex]intValue]; // edited
NSLog(#"My random number-%i",myNumber);//this is your generated random number
[myMutableArray removeObjectAtIndex:randomIndex];
}
I guess this would do the tric, But if you do rmember NSMutableArray cannot take Primitive data type, just Objects like NSNumber.
EDIT
this line is not written and is justifying that why i am converting the NSNumber back to an interger because while adding the integer in the Array it has to be converted to a NSNumber|
[ myMutableArray addObject:[NSNumber numberWithInt:2]];
So in the for loop when i am getting the object from myMutableArray i am getting an NSNumber and to simplify it i casted that Object (NSNumber object) back to an integer.
From Apple's documentation:
A set stores distinct values of the same type in a collection with no
defined ordering.
This seems to be exactly what you are after, so making an array seems a bit ill-advised...
var values : Set<Int> = []
var value : Int {
return Int(arc4random() % 6 + 1)
}
while values.count < 6 {
values.insert(value)
}
And you probably want to have a look at those values somewhere down the line:
for value in values {
println(value)
}
Just store the last random number in a variable and check the next random number against it in a while loop. While the new random number is the same as the last random number, generate a new random number. Once the new random number generated is not the same as the last random number the while loop ends and we update the last random number.
var lastRandomNumber = 0
var newRandomNumber = 0
func gernerateRandomNumber() {
newRandomNumber = Int(arc4random_uniform(5)+1)
while newRandomNumber == lastRandomNumber {
newRandomNumber = Int(arc4random_uniform(5)+1)
}
lastRandomNumber = newRandomNumber
}

Dictionary won't let me append a string to its values

I'm trying to create a function which takes an array of names, and sorts it in a dictionary with letters and names as keys and values. But now the dictionary wont let me append the string to the values. My code looks like this:
func listCounter(usernames: [String])->Dictionary <String,[String]> {
var dict=Dictionary<String,[String]>()
var letterList = [String]()
for user in usernames{
var index = user.substringToIndex(advance(user.startIndex,1))
index = index.lowercaseString as String
if find(letterList, index) != 0{
dict[index] += [user]
}else{
dict[index] = [user]
letterList += [index]
}
}
return dict
}
The error comes in the line where I'm trying to add the new string to the dictionary, it says: "Cannot invoke '+=' with an argument list of type '$T4,$T6'" which is telling me there's something wrong with the types, but I don't know how to fix it.
Any suggestions on how to solve this would be appreciated.
That happens because a dictionary lookup always returns an optional - since the preceding if should ensure that the element exists, you can safely apply the forced unwrapping operator on that:
dict[index]! += [user]
However running a test on a playground resulted in a runtime exception - I think this condition:
if find(letterList, index) != 0 {
is not reliable.
I replaced with an explicit check for the key existence, and it worked:
if dict[index] != nil {
dict[index]! += [user]
Note: I didn't use optional binding like this:
if var element = dict[index] {
element += [user]
because arrays are value types, copied by value. Assigning the array to a variable actually creates a copy of it, so the addition is done on the copy, leaving the original array unchanged.
if find(letterList, index) != 0 { ... }
should actually be
if find(letterList, index) != nil { ... }
or just
if contains(letterList, index) { ... }
But #Antonio has already explained the error message and given a solution. As an alternative, you can also take advantage of
optional chaining:
for user in usernames {
var index = user.substringToIndex(advance(user.startIndex,1))
index = index.lowercaseString as String
if (dict[index]?.append(user)) == nil {
dict[index] = [user]
letterList.append(index)
}
}
How does it work? If dict[index] is nil, then
dict[index]?.append(user)
does nothing and returns nil, so that the if-block is executed.
Otherwise
dict[index]?.append(user)
appends the user to the array in dict[index] and the if-block
is not executed.
You could also write it as a one-liner, using the "nil-coalescing operator" ??:
for user in usernames {
var index = user.substringToIndex(advance(user.startIndex,1))
index = index.lowercaseString as String
dict[index] = (dict[index] ?? []) + [user]
}
Here, dict[index] ?? [] evaluates to the dictionary value if that
already exists, and to an empty array otherwise. And the array
of all indices can also be computed after the loop with
letterList = Array(dict.keys)

Resources