How to customise Indexpath.row value in iOS swift - ios

I want to retrieve only some of the index items in a table view.
eg: I have:
let array1 = ["one","two","three","four","two","one","three"]
let array2 = ["dog","cat","lion","tiger","elephant","eagle","peacock"]
var duplicatedDict : [String:[Int]] = [:]
for (index,dateString) in array1.enumerated() {
if(duplicatedDict[dateString] == nil){
duplicatedDict[dateString] = [index]
}else{
duplicatedDict[dateString]?.append(index)
}
}
print(duplicatedDict)
//output : ["three": [2, 6], "four": [3], "one": [0, 5], "two": [1, 4]]
When I get the value "three" then I have to get only 2nd and 6th (2 and 6 is index value of the string "three" in array1) index of array2.
Output should be ("lion and peacock") in my UItableView row. How can I customise my tableview to get the above output?

The generation of duplicatedDict can be greatly simplified using the new default parameter in Swift4:
let array1 = ["one","two","three","four","two","one","three"]
let array2 = ["dog","cat","lion","tiger","elephant","eagle","peacock"]
var duplicatedDict = [String:[Int]]()
for (index, val) in array1.enumerated() {
duplicatedDict[ val, default:[] ].append(index)
}
print(duplicatedDict)
Once you have that, its easy to get the corresponding elements from array2:
if let indexes = duplicatedDict["three"] {
let animals = indexes.map { array2[$0] }
print(animals)
}

Related

Improving on the efficiency of my filtering of arrays with potentially hundreds of thousands of elements

I have an array of numbers. I want to find those in array1 that aren't also in array2, like this:
var array1 = [1, 2, 3, 4]
var array2 = [2, 4, 5, 6]
var result = [1, 3]
I've solved the problem by looping through all the numbers in the array2 and adding them to a dictionary. Then I loop through array1 and add those that aren't in the dictionary to the result array:
var result: [Int] = []
var numbersDict: [Int : Bool] = [:]
for element in array2 {
numbersDict[element] = true
}
for element in array1 {
if numbersDict[element] == nil {
result.append(element)
}
}
I also want to find those in array2 that aren't in array1
var array1 = [1, 2, 3, 4]
var array2 = [2, 4, 5, 6]
var result = [5, 6]
I've solved this like this:
var result: [Int] = []
var numbersDict: [Int : Bool] = [:]
for element in array1 {
numbersDict[element] = true
}
for element in array2 {
if numbersDict[element] == nil {
result.append(element)
}
}
How can I do this in the most efficient way? Assuming that these arrays could potentially be tens if not hundreds of thousands of numbers long. Should I be using sorting?
Just use Set.
Example which gets elements in array1 but not in array2:
let array1: Set = [1, 2, 3, 4]
let array2: Set = [2, 4, 5, 6]
let result = array1.subtracting(array2)
print(result)
// Prints: [1, 3] <- Order may vary since it is a set
Just switch the two sets around to get the opposite result, of in array2 but not in array1.
There are lots of Set operations, another one is intersection(_:):
let result = array1.intersection(array2)
print(result)
// Prints: [2, 4] <- Again, no order

How to get the items of an array based on the indexes stored in another array

I have two arrays:
let a = ["apple","banana","orange","pomelo","kiwi","melon"]
let b = [1, 2, 4]
a contains all the items and b contains the indexes of the ones I'm interested in.
So I would like to create a function to extract the items at the indexes specified in array b.
I can do tis with for loops:
for i in 0...a.count-1{
if i == b[i]{
print(a[i])
}
}
To make it clear, the desired output would be:
banana orange kiwi
The problem is that with big numbers the for loop would be too slow.
I would like to know if there exists something with a lower complexity.
You can simply map the indices and return the associated elements:
let aa = ["apple","banana","orange","pomelo","kiwi","melon"]
let bb = [1, 2, 4]
let elements = bb.map { aa[$0] }
print(elements) // ["banana", "orange", "kiwi"]
Or extending RandomAccessCollection protocol:
extension RandomAccessCollection {
func elements(at indices: [Index]) -> [Element] { indices.map { self[$0] } }
}
let a = ["apple","banana","orange","pomelo","kiwi","melon"]
let b = [1, 2, 4]
let elements = a.elements(at: b) // ["banana", "orange", "kiwi"]

Swift 3 - Compare two unequal length arrays and append placeholder values in it to make them equal

My first array is
arr1 = [1, 2, 3, 4 , 5]
My second array is
arr2 = [2, 3, 4]
I want to compare arr1 against arr2 and output a third array with the output
arr3 = ["No match", 2, 3, 4, "No match"]
So that I have added a placeholder value at indices where arr1 and arr2 dont match. Arr1 and arr2 will not always be sorted.
How do i go about this in Swift 3? Can't come up with a loop that will work :/
a simple solution will be
let arr1 = [1,2,3,4,5,6]
let arr2 = [2,3,4]
var arr3 = [String]()
for value in arr1{
if arr2.contains(value){
arr3.append("\(value)")
} else {
arr3.append("No Match")
}
}
one line solution would be
let results = arr1.map {arr2.contains($0) ? "\($0)" : "No Match"}
you can try this :
let arr1 = [1,2,7,3,4,5]
let arr2 = [2,3,4,7]
var arr3 = [Any]()
var count = Int()
let sortedArr1 = arr1.sorted()
let sortedArr2 = arr2.sorted()
let arrCount1 = sortedArr1.count
let arrCount2 = sortedArr2.count
if arrCount1 > arrCount2 {
count = arrCount1
}else {
count = arrCount2
}
for i in 0..<count {
if sortedArr2.contains(sortedArr1[i]){
arr3.append(sortedArr1[i])
}else {
arr3.append("Not Matched")
}
}
When you print the output array it will give you the desired result:
print(arr3) //Outputs :["Not Matched", 2, 3, 4, "Not Matched", 7]
Or the one line code will be like as follows:
let arr3 = sortedArr1.map {sortedArr2.contains($0) ? "\($0)" : "Not Matched"}
print(arr3) //Outputs :["Not Matched", 2, 3, 4, "Not Matched", 7]
if you want array of string instead of any. you can try this
let arr1 = [1, 2, 3, 4 , 5]
let arr2 = [2, 3, 4]
let test = arr1.map{
(item) -> String in
if arr2.contains(item){
return "\(item)"
}else{
return "No match"
}
}
print(test)//["No match", "2", "3", "4", "No match"]

Get Subset of array based on the occurrence of elements

I have an array like:
var arr = [4,1,5,5,3]
I want to fetch subset from the array based on the occurrence of elements in it.
For example:
Elements with frequency 1 is {4,1,3}
Elements with frequency 2 is {5,5}
I followed this StackOverflow question but unable to figure out how to do the above thing.
Is there any way I can do this?
You can use an NSCountedSet to get the count of all elements in arr, then you can build a Dictionary, where the keys will be the number of occurencies for the elements and the values will be Arrays of the elements with key number of occurences. By iterating through Set(arr) rather than simply arr to build the Dictionary, you can make sure that repeating elements are only added once to the Dictionary (so for instance with your original example, 5 wouldn't be added twice as having a frequency of 2).
For the printing, you just need to iterate through the keys of the Dictionary and print the keys along with their corresponding values. I just sorted the keys to make the printing go in ascending order of number of occurences.
let arr = [4,1,5,5,3,2,3,6,2,7,8,2,7,2,8,8,8,7]
let counts = NSCountedSet(array: arr)
var countDict = [Int:[Int]]()
for element in Set(arr) {
countDict[counts.count(for: element), default: []].append(element)
}
countDict
for freq in countDict.keys.sorted() {
print("Elements with frequency \(freq) are {\(countDict[freq]!)}")
}
Output:
Elements with frequency 1 are {[4, 6, 1]}
Elements with frequency 2 are {[5, 3]}
Elements with frequency 3 are {[7]}
Elements with frequency 4 are {[2, 8]}
Swift 3 version:
let arr = [4,1,5,5,3,2,3,6,2,7,8,2,7,2,8,8,8,7]
let counts = NSCountedSet(array: arr)
var countDict = [Int:[Int]]()
for element in Set(arr) {
if countDict[counts.count(for: element)] != nil {
countDict[counts.count(for: element)]!.append(element)
} else {
countDict[counts.count(for: element)] = [element]
}
}
for freq in countDict.keys.sorted() {
print("Elements with frequency \(freq) are {\(countDict[freq]!)}")
}
You just need to get the occurrences of the elements and filter the elements that only occurs once or more than once as shown in this answer:
extension Array where Element: Hashable {
// Swift 4 or later
var occurrences: [Element: Int] {
return reduce(into: [:]) { $0[$1, default: 0] += 1 }
}
// // for Swift 3 or earlier
// var occurrences: [Element: Int] {
// var result: [Element: Int] = [:]
// forEach{ result[$0] = (result[$0] ?? 0) + 1}
// return result
// }
func frequencies(where isIncluded: (Int) -> Bool) -> Array {
return filter{ isIncluded(occurrences[$0] ?? 0) }
}
}
Playground Testing:
let arr = [5, 4, 1, 5, 5, 3, 5, 3]
let frequency1 = arr.frequencies {$0 == 1} // [4, 1]
let frequency2 = arr.frequencies {$0 == 2} // [3, 3]
let frequency3orMore = arr.frequencies {$0 >= 3} // [5, 5, 5, 5]
This is it:
func getSubset(of array: [Int], withFrequency frequency: Int) -> [Int]
{
var counts: [Int: Int] = [:]
for item in array
{
counts[item] = (counts[item] ?? 0) + 1
}
let filtered = counts.filter{ $0.value == frequency}
return Array(filtered.keys)
}
This is pure Swift (not using good old Next Step classes) and is using ideas from the SO link you supplied.
The counts dictionary contains the frequencies (value) of each of the int-values (key) in your array: [int-value : frequency].

Two arrays in key and value in Dictionary swift

I have two Int arrays, for example:
array1 = [1, 2, 3, 4] as Int
array2 = [10, 20, 30, 40] as Int
for work I need create Dictionary where Key - it's element from array1 and Value - it's element from array2, in my example - [1:10, 2:20, 3:30, 4:40] as [Int:Int].
So, when I create loop:
for i in 0..<arrayOfKeys.count {
dictionaryOfData[arrayOfKeys[i]] = arrayOfValues[i]
}
i see only last [4:40], but I know that I must have the Dictionary with 4 keys-values.
Give me, please, advise, how to do it in swift?!
upd, i find my problem - keys MUST be unique! So, thanks a lot for your answer and i knew about zip in swift
Try this:
let array1 = [1, 2, 3, 4]
let array2 = [10, 20, 30, 40]
var dict = [Int: Int]()
zip(array1, array2).forEach { dict[$0] = $1 }
print(dict)
Few solutions off the top of my head:
Init Arrays + Dict
let arrayOfValues = [1,2,3,4]
let arrayOfKeys = [1,2,3,4]
var arrayOfDict = [Int:Int]()
For loop solution:
for i in 0..<arrayOfKeys.count {
if i < arrayOfValues.count {
let key = arrayOfKeys[i]
let value = arrayOfValues[i]
arrayOfDict[key] = value
}
}
Using zip method solution:
for (key, value) in zip(arrayOfValues, arrayOfKeys) {
arrayOfDict[key] = value
}
From apple docs:
zip: A sequence of pairs built out of two underlying sequences, where
the elements of the ith pair are the ith elements of each underlying
sequence.(iOS (9.0 and later))
If you can't use Zip you can enumerate your array if both arrays have the same number of elements:
let array1 = [1, 2, 3, 4]
let array2 = [10, 20, 30, 40]
var result: [Int:Int] = [:]
array1.enumerate().forEach{ result[$0.element] = array2[$0.index] }
result // [2: 20, 3: 30, 1: 10, 4: 40]
Here is an updated answer for Swift 4 taken from www.tutorialspoint.com:
let cities = ["Delhi", "Bangalore", "Hyderabad"]
let distances = [2000, 10, 620]
let cityDistanceDict = Dictionary(uniqueKeysWithValues: zip(cities, distances))

Resources