Is there an equivalent of JavaScript's indexOf for Rust arrays? - arrays

var fruits = ["Banana", "Orange", "Apple", "Mango"];
var index = fruits.indexOf("Apple");
let fruits = ["Banana", "Orange", "Apple", "Mango"];
let index = fruits.???
If there is no equivalent, maybe you can point me in the right direction? I found this example, but it's for vectors, not arrays.

You can use the method position on any iterator. You can get an iterator over an array with the iter() method. Try it like this:
let fruits = ["Banana", "Orange", "Apple", "Mango"];
let res1 = fruits.iter().position(|&s| s == "Apple");
let res2 = fruits.iter().position(|&s| s == "Peter");
println!("{:?}", res1); // outputs: Some(2)
println!("{:?}", res2); // outputs: None

Related

Filter array with prefix

I have an array, of type String:
var Arr = ["apple", "banana", "orange", "grapes", "yellow banana", "urban"]
How do I filter every word in array that has a prefix of my keyword?
Now I have this:
.filter { $0.contains(keyword) }
.sorted { ($0.hasPrefix(keyword) ? 0 : 1) < ($1.hasPrefix(keyword) ? 0 : 1) }
But if I have keyword "ban", it will return "banana", "yellow banana", and "urban".
I need only to filter prefix of every word in array element, to get "banana" and "yellow banana".
You can use a regular expression which checks if the keyword
occurs at a word boundary (\b pattern):
let array = ["apple", "banana", "orange", "grapes", "yellow banana", "urban"]
let keyword = "ban"
let pattern = "\\b" + NSRegularExpression.escapedPattern(for: keyword)
let filtered = array.filter {
$0.range(of: pattern, options: .regularExpression) != nil
}
print(filtered) // ["banana", "yellow banana"]
And for a case-insensitive search use
options: [.regularExpression, .caseInsensitive]
instead.
Performance Note
I just want to refer to the Time-Complexity caused by filtering the array for matching.
For example :
private var words: [String]
func words(matching prefix: String) -> [String]
{
return words.filter { $0.hasPrefix(prefix) }
}
words(matching:) will go through the collection of strings and return
the strings that match the prefix.
If the number of elements in the words array is small, this is a
reasonable strategy. But if you’re dealing with more than a few
thousand words, the time it takes to go through the words array will
be unacceptable. The time complexity of words(matching:) is O(k*n),
where k is the longest string in the collection, and n is the number of
words you need to check.
Trie data structure has excellent performance characteristics for
this type of problem.
Reference : https://www.raywenderlich.com/892-swift-algorithm-club-swift-trie-data-structure
You will need to first break up your string into words using enumerateSubstrings method and then you can check if any of the words contains the keyword prefix:
extension String {
var words: [String] {
var words: [String] = []
enumerateSubstrings(in: startIndex..<endIndex, options: .byWords) { word,_,_,_ in
guard let word = word else { return }
words.append(word)
}
return words
}
}
let arr = ["apple", "banana", "orange", "grapes", "yellow banana", "urban"]
let keyword = "ban"
let filtered = arr.filter { $0.words.contains(where: {$0.hasPrefix(keyword)}) }
filtered // ["banana", "yellow banana"]
Alternatively in Swift 3+:
let array = ["apple", "banana", "orange", "grapes", "yellow banana", "urban"]
let keyword = "ban"
let filtered = array.filter {
$0.components(separatedBy: " ").first { $0.hasPrefix(keyword) } != nil
}
print(filtered) // ["banana", "yellow banana"]
You can filter array with hasPrefix as follows:
// I Use two arrays, actualArray with original data and filteredArray contains data after filtration. You can use whatever is best for your scenario
filteredArray = actaulArray.filter({ $0.hasPrefix(searchBar.text!) })

Getting values in double array from index. Swift

I have a collection view made up of 4 sections.
Each section is an array of strings, like this:
var picList: [String] = ["Bird", "Cat", "Cow", "Dog", "Duck", "Elephant", "Fish", "Giraffe", "Lion", "Mouse", "Sheep", "Snake" ]
var vehiclesList: [String] = ["Airplane", "Ambulance", "Boat", "Bus", "Car", "Fire_Engine", "Helicopter", "Motorcycle", "Tank", "Tractor", "Train", "Truck" ]
var fruitsList: [String] = ["Apple", "Banana", "Grapes", "Mango", "Orange", "Peach", "Pineapple", "Strawberry", "Watermelon" ]
var bodyPartsList: [String] = ["Arm", "Ear", "Eye", "Face", "Feet", "Hand", "Hair", "Legs", "Mouth", "Nose" ]
I created a UITapGestureRecognizer for the cell, that when I click on the cell, I get the index.
Here is the tapMethod
func handleTap(sender: UITapGestureRecognizer) {
print("tap")
if let indexPath = self.collectionView?.indexPathForItem(at: sender.location(in: self.collectionView)) {
let cell = collectionView?.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! PicViewCell
print("index path: + \(indexPath)")
} else {
print("")
}
}
Now the index prints like this [0,0] (if I press on the first item, ie bird). [2,4] if I press on the 4th item in the 2nd secion (ie mango). But I don't know how to translate the index, to get the corresponding string value. I mean something like this:
var itemName: String = [2,4] (and itemName would be mango)
I'm new to swift, so any help would be great.
Thanks so much.
What you need is an array of arrays, aka a 2D array - [[String]].
var array = [picList, vehicleList, fruitsList, bodyPartsList]
Then, you can access this with 2 indices like this:
var itemName = array[2][4]
You can create a two dimensional array, and add there your lists, indexpath.section will be the index of list and indexpath.item will be the index in thst list

Using a variable content as an array name

In swift 3.0, I would like to concatenate strings (string1 & string2) and use the resulting string (string3) as the name of the array I want to access.
let fruitsArray = ["apple", "orange", "banana"]
let appleArray = ["red", "green", "yellow"]
let string1 = "apple"
let string2 = "Array"
let string3 = string1 + string2
let string4 = string3[1]
Of course there is an error message "subscript is unavailable ...)
What is the proper way to do this? Many thanks to you all.
What you want is possible using some form of introspection but it's a bad practice and extremely clumsy anyhow. You should remodel your data, for example, use a Dictionary:
let data = [
"fruitsArray" : ["apple", "orange", "banana"],
"appleArray": ["red", "green", "yellow"]
]
let string1 = "apple"
let string2 = "Array"
let string3 = string1 + string2
if let array = data[string3] {
let string4 = array[1]
print(string4)
} else {
print("Key not found")
}
As #CodeDifferent writes in his/her answer, you might want to consider remodelling your data as this type of runtime property accessing is not very "Swifty".
If you're only interesting in reading data for the sake of debugging, however, you could make use of the Mirror structure to perform runtime introspection on the data type that owns the array properties.
E.g.:
struct Foo {
let fruitsArray = ["apple", "orange", "banana"]
let appleArray = ["red", "green", "yellow"]
}
func attemptToReadStringArrayProperty(_ name: String, fromFoo foo: Foo) -> [String]? {
return Mirror(reflecting: foo).children
.flatMap { ($0 ?? name + ".") == name ? ($1 as? [String]) : nil }.first
}
/* example usage/debugging */
let string1 = "apple"
let string2 = "Array"
let string3 = string1 + string2
let foo = Foo()
if let strArr = attemptToReadStringArrayProperty(string3, fromFoo: foo) {
strArr.forEach { print($0) }
} /* red
green
yellow */
Naturally, you could apply this approach for non-debugging purposes, but I wouldn't recommend it.

How to update merged array after one is being updated in Swift

In the following example, how can I make mix to update to reflect changes made to any of the merged arrays?
var fruits = ["Apple", "Orange", "Bannana"]
var cars = ["Cobalt", "Durango", "Jetta"]
var mix = fruits + cars
print(fruits)
print(cars)
print(mix)
cars.append("Mustang") // cars array modification
print(mix) // how to update mix to show Mustang?
Computed variable is what are you looking for, I believe:
var fruits = ["Apple", "Orange", "Bannana"]
var cars = ["Cobalt", "Durango", "Jetta"]
var mix: [String] {return fruits + cars}
print(mix)
//["Apple", "Orange", "Bannana", "Cobalt", "Durango", "Jetta"]
cars.append("Mustang") // cars array modification
print(mix)
//["Apple", "Orange", "Bannana", "Cobalt", "Durango", "Jetta", "Mustang"]
This would be the simplest way (perhaps not the most efficient)...
var fruits = ["Apple", "Orange", "Bannana"]
var cars = ["Cobalt", "Durango", "Jetta"]
var mix = fruits + cars
print(fruits)
print(cars)
print(mix)
cars.append("Mustang") // cars array modification
mix = fruits + cars
print(mix) // Now shows Mustang.
mix does not contain a reference back to cars so you can't expect it to be dynamically updated when cars is updated.

Swift 2 How to create a random dictionary from 2 similar arrays

I'm using xcode 7, and I am wondering how to create a randomized dictionary from two similar arrays.
For example
var array1 = ["apple", "banana", "orange", "strawberry", "cherry"]
var array2 = ["apple", "banana", "orange", "strawberry", "cherry"]
I then want the code to create a random dictionary like so:
var dict = ["apple": "banana", "banana": "apple", "orange": "cherry", "strawberry": "orange", "cherry": "strawberry"]
Also, I don't want to have both value and key to be the same, ie no "apple": "apple".
I'm relatively new to coding. Any help would be greatly appreciated :)
You can use shuffle function from Nate Cook's answer to shuffle values array and then simply fill dictionary with keys and values:
var keys = ["apple", "banana", "orange", "strawberry", "cherry"]
var values = keys
values.shuffle()
var d = [String: String]()
for (index, item) in keys.enumerate() {
d[item] = values[index]
}
The advantage of this solution that it's O(n) (execution time and consumed memory linearly depends from number of items).
Your particular example is a bit contrived as there is really no point in dealing with two identical arrays, you can simply use one. I guess something like this should do the trick:
var fruits = ["apple", "banana", "orange", "strawberry", "cherry"]
var dict = [String: String]()
for (keyIndex, key) in fruits.enumerate() {
var valueIndex: Int {
var index: Int
repeat {
index = Int(arc4random_uniform(UInt32(fruits.count)))
} while index == keyIndex || dict.values.contains(fruits[index])
return index
}
dict[key] = fruits[valueIndex]
}

Resources