Getting values in double array from index. Swift - arrays

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

Related

Cannot assign value of type '[String]' to type '[[String : Any]]'

Swift Xcode version 13.2.1
Here we have two Arrays,(1)var dicSearch=String and (2)var searchingDic: [[String: Any]]=[] I want to assign searchingDic to dicSearch when i implement it than it show error like, Cannot assign value of type '[String]' to type '[[String : Any]]'
here's my code, please anyone help!
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
searchingDic = dicSearch.filter{filtering in
let filterService = filtering["fName"] as? String
return((filterService?.lowercased().contains(searchText.lowercased()))!)
}
It looks like you are trying to create a filtered list based on a search term, but your dicSearch type is an array of strings (i.e: [String]), while your searchingDic is an array of dictionaries (i.e: [[String : Any]]).
This might be confusing when coming from a different language, but in Swift, the following declaration is a dictionary:
var dict: [String: Any] = [
"key1": "value1",
"key2": "value2",
]
so the following:
var arrayOfdicts: [[String: Any]] = [
["foo": "bar"],
["apples": "oranges"],
dict
]
is actually an array, containing a list of dictionaries, notice how I've put the dict declared above in the second array.
The compiler is telling you that you cannot assign a '[String]' to type '[[String : Any]]'
because this:
// example to an array of strings
var fullList: [String] = [
"apples",
"bananas",
"cucumbers"
]
// is not the same as
var arrayOfdicts: [[String: Any]] = [
["foo": "bar"],
["apples": "oranges"],
dict
]
The Array#filter method, iterates the array itself, and returns a new array with only the elements that return true in the return statement.
so either both your arrays need to be [String] or both your arrays need to be [[String:Any]]
example for String arrays:
// array
var fullList: [String] = [
"apples",
"bananas",
"cucumbers"
]
var filteredList: [String] = []
var searchTerm = "b"
filteredList = fullList.filter{ item in
let value = item
return value.lowercased().contains(searchTerm)
}
print(filteredList) // prints ["bananas", "cucumbers"]
an example for filtering with array of dictionaries:
var people: [[String: Any]] = [
["name": "Joe"],
["name": "Sam"],
["name": "Natalie"],
["name": "Eve"]
]
var filteredPeople: [[String: Any]] = []
var nameFilter = "a"
filteredPeople = people.filter{ item in
let value = item["name"] as! String
return value.lowercased().contains(nameFilter)
}
print(filteredPeople) // prints [["name": "Sam"], ["name": "Natalie"]]
Hope this helps :)

compare multiple arrays for same elements in swift

I'm new to swift and programming in general. I have multiple arrays of names in a database and I need to check for same names in these arrays.
I've found some solutions to compare two arrays, but not multiple so I wrote some additional code.
But performance wise it's not the best practice I think. And also not the best way to add first all the names and then remove the duplicates..
Does anyone has any better ideas/solutions for my problem?
Code:
import UIKit
let array1 = ["Max", "Peter","Kathrin", "Sara", "Kirsten", "Mike", "Elon"] // Peter, Kathrin, Mike, Sara
let array2 = ["Pamela", "Chris", "James", "Sebastian", "Mike"] // Mike, Chris
let array3 = ["John", "Daniel", "Susan", "Mathias", "Mike", "Donald"] // Mike
let array4 = ["Tim", "Kathrin", "Alan", "Chris", "Amy", "Sara"] // Kathrin, Chris
let array5 = ["Cara", "Charly", "Emily", "Maja", "Peter", "Sara"] // Peter, Sara
// Output should be: Peter, Kathrin, Mike, Sara, Chris
var array = [Array<String>]()
array.append(array1)
array.append(array2)
array.append(array3)
array.append(array4)
array.append(array5)
var names = [String]()
for i in 0...array.count - 2 {
for z in 1...array.count - 1 {
if z + i < array.count {
let commonElements = Array(Set(array[i]).intersection(Set(array[z+i])))
names.append(contentsOf: commonElements)
}
}
}
print(names.removeDuplicates())
Extension:
extension Array where Element: Hashable {
func removeDuplicates() -> [Element] {
var result = [Element]()
for value in self {
if result.contains(value) == false {
result.append(value)
}
}
return result
}
}
If your intent is to just check if a name occurs in more than one collection I think the best way to approach this is creating a single collection with all the names and filter the duplicates as shown in this post
let array1 = ["Max", "Peter","Kathrin", "Sara", "Kirsten", "Mike", "Elon"]
let array2 = ["Pamela", "Chris", "James", "Sebastian", "Mike"]
let array3 = ["John", "Daniel", "Susan", "Mathias", "Mike", "Donald"]
let array4 = ["Tim", "Kathrin", "Alan", "Chris", "Amy", "Sara"]
let array5 = ["Cara", "Charly", "Emily", "Maja", "Peter", "Sara"]
var names: [String] = []
names.append(contentsOf: array1)
names.append(contentsOf: array2)
names.append(contentsOf: array3)
names.append(contentsOf: array4)
names.append(contentsOf: array5)
extension RangeReplaceableCollection where Element: Hashable {
var duplicates: Self {
var set: Set<Element> = []
var filtered: Set<Element> = []
return filter { !set.insert($0).inserted && filtered.insert($0).inserted }
}
}
// Output should be: Peter, Kathrin, Mike, Sara, Chris
print(names.duplicates) // ["Mike", "Kathrin", "Chris", "Sara", "Peter"]

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!) })

Dictionaries [String: [String]] in Swift

I have a dictionary that looks like this:
var dict = [String: [String]]()
I want to be able to add multiple arrays for a single key. This works fine:
dict["hello"] = ["item 1"]
But when I assign a new array the previous value is obviously overwritten - we want to avoid that:
dict["hello"] = ["item 2"] // overwrites item 1 – how to avoid overwriting?
So I tried to use the append method, but this returns nil:
dict["hello"]?.append("test") // does nothing? output: ()
How can I append strings to the array (value) of a certain key in Swift?
First of all...
... you don't really want this
I want to be able to add multiple arrays for a single key.
Instead I think you want...
... to add a string to the array associated to a given string
Example
In other words you want to go from this
["hello":["item 1"]]
to this
["hello":["item 1", "item 2"]]]
So, how to do it?
Let's begin with your dictionary
var dict = [String: [String]]()
dict["hello"] = ["item 1"]
Now you need to extract the array associated to the hello key
var list = dict["hello"] ?? []
adding a string to it
list.append("item 2")
and finally adding the updated array back into the dictionary
dict["hello"] = list
That's it
This is what your code does
dict["hello"] = ["item 1"] - This sets hello to ["item 1"]
dict["hello"] = ["item 2"] - This sets hello to ["item 2"]
This is just like a variable, for example:
var hello = Array<String>()
hello = ["item 1"] // prints out ["item 1"]
hello = ["item 2"] // prints out ["item 2"]
This is what is happening with your dictionary. You are overriding any stored data with new data.
The problem with appending. This only works if there is already an array at that key.
dict["hello"]?.append("test") This wouldn't work.
But this would.
dict["hello"] = ["test 1"]
dict["hello"]?.append("test")
print(dict) // prints out ["dict":["test 1","test"]]
What you need to do
var dict = Dictionary<String,Array<String>>()
func add(string:String,key:String) {
if var value = dict[key] {
// if an array exist, append to it
value.append(string)
dict[key] = value
} else {
// create a new array since there is nothing here
dict[key] = [string]
}
}
add(string: "test1", key: "hello")
add(string: "test2", key: "hello")
add(string: "test3", key: "hello")
print(dict) // ["hello": ["test1", "test2", "test3"]]
Dictionary Extension
extension Dictionary where Key == String, Value == Array<String> {
mutating func append(_ string:String, key:String) {
if var value = self[key] {
// if an array exist, append to it
value.append(string)
self[key] = value
} else {
// create a new array since there is nothing here
self[key] = [string]
}
}
}
How to use
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
var dict = Dictionary<String,Array<String>>()
dict.append("first", key: "hello")
dict.append("second", key: "hello")
dict.append("thrid", key: "hello")
dict.append("one", key: "goodbye")
dict.append("two", key: "goodbye")
print(dict) // ["hello": ["first", "second", "thrid"], "goodbye": ["one", "two"]]
}
Please try this thing and let me know if this is what you require
import UIKit
var dict = [String: [String]]()
if var value = dict["hello"]{
value.append("Hi")
dict["hello"] = value
}else{
dict["hello"] = ["item 1"]
}
Other people have the correct solution. Here is a quick shorthand for the same answer.
var dict = [String: [String]]()
dict["hello"] = (dict["hello"] ?? []) + ["item 1"]
dict["hello"] = (dict["hello"] ?? []) + ["item 2"]
In Swift 4, this will be
var dict = [String: [String]]()
dict["hello"] = dict["hello", default: []] + ["item 1"]
dict["hello"] = dict["hello", default: []] + ["item 2"]

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