Access and modify easily Array of Dictionaries in Swift - arrays

I have this structure: [String: [String: Double]]()
Specifically, something like that: var dictionaries = ["GF": ["ET": 4.62, "EO": 21.0],"FD": ["EE": 80.95, "DE": 0.4]]
How can I easily access and modify nested dictionaries?
EXAMPLE UPDATED: I want to append "TT": 6 at FD and later I want to append another dictionary inside the array. At the end I'll print the results.
for (key,value) in dictionaries {
// if array contains FD, add the record to FD
if key.contains("FD") {
dictionaries["FD"]!["TT"] = 6
}
else {
// if array doesn't contain FD, add FD and add the record to it
dictionaries = dictionaries+["FD"]["TT"] = 6 // <-- I know that it's wrong but I want to achieve this result in this case.
}
}
Result of print will be:
GF -> ET - 4.62, EO - 21.0
FD -> EE - 80.95, DE - 0.4, TT - 6
MISSION: I need to append new dictionary records like in the example above, update existing ones in a simple and straightforward way, loop easily through records to read the values and print them out.
Can anyone help me? Never had the chance to manage dictionaries in Swift since now.

It is not clear what exactly you need but the exercise amused me, so I came up with this solution: we extend Dictionary so that it provides convenience methods if it is a nested dictionary.
First, because of Swift idiosyncrasies, we have to create a dummy protocol to "mark" Dictionary¹:
protocol DictionaryProtocol {
associatedtype Key: Hashable
associatedtype Value
subscript(key: Key) -> Value? { get set }
var keys: LazyMapCollection<[Key : Value], Key> { get }
}
extension Dictionary: DictionaryProtocol {}
Basically, just copy-paste² all declarations you need later from Dictionary to DictionaryProtocol.
Then, you can happily extend away. For instance, add a two-parameter subscript:
extension Dictionary where Value: DictionaryProtocol {
typealias K1 = Key
typealias K2 = Value.Key
typealias V = Value.Value
subscript(k1: K1, k2: K2) -> V? {
get {
return self[k1]?[k2]
}
set {
if self[k1] == nil {
self.updateValue([K2: V]() as! Value, forKey: k1)
}
self[k1]![k2] = newValue
}
}
}
Or an alternative pretty-print³:
extension Dictionary where Value: DictionaryProtocol {
func pretty() -> String {
return self.keys.map { k1 in
let row = self[k1]!.keys.map { k2 in
return "\(k2) - \(self[k1]![k2]!)"
}.joined(separator: ", ")
return "\(k1) -> \(row)"
}.joined(separator: "\n")
}
}
You can also create a type alias for this special dictionary:
typealias D2Dictionary<K: Hashable, V> = Dictionary<K, Dictionary<K, V>>
Going back to the example in your question:
var dictionary = D2Dictionary<String, Double>()
dictionary["GF", "ET"] = 4.62
dictionary["GF", "EO"] = 21.0
dictionary["FD", "EE"] = 80.95
dictionary["FD", "DE"] = 0.4
dictionary["FD", "TT"] = 6
print(dictionary.pretty())
// > GF -> ET - 4.62, EO - 21.0
// > FD -> EE - 80.95, DE - 0.4, TT - 6.0
Background: Only protocols can be used in type bounds on extension conditions.
Make sure to get the types right. If we write var keys: [Key] { get }, for instance, the compiler dies with a seg fault.
Unfortunately, extension Dictionary: CustomStringConvertible where Value: DictionaryProtocol { ... } is not allowed, for whatever reason.

It'll be much simpler if you have the key "FD" you can use
dictionaries["FD"]!["TT"] = 6
to add a new value ["TT":6] or modify existing value of TT to 6. Note that the ! between ["FD"]!["TT"] assumes that ["FD"] exists regardless. You need to check if ["FD"] exists otherwise. Like:
if dictionaries["FD"] != nil {
dictionaries["FD"]!["TT"] = 6
} else {
dictionaries["FD"] = ["TT" : 6]
}
If you need to look for the key you will have to run the entire dictionary like you already tried, but dictionaries support fast enumeration for key and values like
for (key,value) in dictionaries {
if key.contains("FD") { //or any other checks you need to identify your key
value["TT"] = 6
}
}

Related

How do I get an array order number of the text give in that array? [duplicate]

I am trying to find an item index by searching a list. Does anybody know how to do that?
I see there is list.StartIndex and list.EndIndex but I want something like python's list.index("text").
As swift is in some regards more functional than object-oriented (and Arrays are structs, not objects), use the function "find" to operate on the array, which returns an optional value, so be prepared to handle a nil value:
let arr:Array = ["a","b","c"]
find(arr, "c")! // 2
find(arr, "d") // nil
Use firstIndex and lastIndex - depending on whether you are looking for the first or last index of the item:
let arr = ["a","b","c","a"]
let indexOfA = arr.firstIndex(of: "a") // 0
let indexOfB = arr.lastIndex(of: "a") // 3
tl;dr:
For classes, you might be looking for:
let index = someArray.firstIndex{$0 === someObject}
Full answer:
I think it's worth mentioning that with reference types (class) you might want to perform an identity comparison, in which case you just need to use the === identity operator in the predicate closure:
Swift 5, Swift 4.2:
let person1 = Person(name: "John")
let person2 = Person(name: "Sue")
let person3 = Person(name: "Maria")
let person4 = Person(name: "Loner")
let people = [person1, person2, person3]
let indexOfPerson1 = people.firstIndex{$0 === person1} // 0
let indexOfPerson2 = people.firstIndex{$0 === person2} // 1
let indexOfPerson3 = people.firstIndex{$0 === person3} // 2
let indexOfPerson4 = people.firstIndex{$0 === person4} // nil
Note that the above syntax uses trailing closures syntax, and is equivalent to:
let indexOfPerson1 = people.firstIndex(where: {$0 === person1})
Swift 4 / Swift 3 - the function used to be called index
Swift 2 - the function used to be called indexOf
* Note the relevant and useful comment by paulbailey about class types that implement Equatable, where you need to consider whether you should be comparing using === (identity operator) or == (equality operator). If you decide to match using ==, then you can simply use the method suggested by others (people.firstIndex(of: person1)).
You can filter an array with a closure:
var myList = [1, 2, 3, 4]
var filtered = myList.filter { $0 == 3 } // <= returns [3]
And you can count an array:
filtered.count // <= returns 1
So you can determine if an array includes your element by combining these:
myList.filter { $0 == 3 }.count > 0 // <= returns true if the array includes 3
If you want to find the position, I don't see fancy way, but you can certainly do it like this:
var found: Int? // <= will hold the index if it was found, or else will be nil
for i in (0..x.count) {
if x[i] == 3 {
found = i
}
}
EDIT
While we're at it, for a fun exercise let's extend Array to have a find method:
extension Array {
func find(includedElement: T -> Bool) -> Int? {
for (idx, element) in enumerate(self) {
if includedElement(element) {
return idx
}
}
return nil
}
}
Now we can do this:
myList.find { $0 == 3 }
// returns the index position of 3 or nil if not found
Swift 5
func firstIndex(of element: Element) -> Int?
var alphabets = ["A", "B", "E", "D"]
Example1
let index = alphabets.firstIndex(where: {$0 == "A"})
Example2
if let i = alphabets.firstIndex(of: "E") {
alphabets[i] = "C" // i is the index
}
print(alphabets)
// Prints "["A", "B", "C", "D"]"
While indexOf() works perfectly, it only returns one index.
I was looking for an elegant way to get an array of indexes for elements which satisfy some condition.
Here is how it can be done:
Swift 3:
let array = ["apple", "dog", "log"]
let indexes = array.enumerated().filter {
$0.element.contains("og")
}.map{$0.offset}
print(indexes)
Swift 2:
let array = ["apple", "dog", "log"]
let indexes = array.enumerate().filter {
$0.element.containsString("og")
}.map{$0.index}
print(indexes)
in Swift 4.2
.index(where:) was changed to .firstIndex(where:)
array.firstIndex(where: {$0 == "person1"})
For custom class, you need to implement the Equatable protocol.
import Foundation
func ==(l: MyClass, r: MyClass) -> Bool {
return l.id == r.id
}
class MyClass: Equtable {
init(id: String) {
self.msgID = id
}
let msgID: String
}
let item = MyClass(3)
let itemList = [MyClass(1), MyClass(2), item]
let idx = itemList.indexOf(item)
printl(idx)
In Swift 4, the firstIndex method can be used. An example of using the == equality operator to find an object in an array by its id:
let index = array.firstIndex{ $0.id == object.id }
note this solution avoids your code needing to conform to the Equitable protocol as we're comparing the property and not the entire object
Also, a note about == vs === since many of the answers posted so far have differed in their usage:
== is the equality operator. It checks if values are equal.
=== is the identity operator. It checks whether two instances of a class point to the same memory. This is different from equality, because two objects that were created independently using the same values will be considered equal using == but not === because they are different objects. (Source)
It would be worth it to read more on these operators from Swift's documentation.
Just use firstIndex method.
array.firstIndex(where: { $0 == searchedItem })
Update for Swift 2:
sequence.contains(element): Returns true if a given sequence (such as
an array) contains the specified element.
Swift 1:
If you're looking just to check if an element is contained inside an array, that is, just get a boolean indicator, use contains(sequence, element) instead of find(array, element):
contains(sequence, element): Returns true if a given sequence (such as
an array) contains the specified element.
See example below:
var languages = ["Swift", "Objective-C"]
contains(languages, "Swift") == true
contains(languages, "Java") == false
contains([29, 85, 42, 96, 75], 42) == true
if (contains(languages, "Swift")) {
// Use contains in these cases, instead of find.
}
Swift 4. If your array contains elements of type [String: AnyObject]. So to find the index of element use the below code
var array = [[String: AnyObject]]()// Save your data in array
let objectAtZero = array[0] // get first object
let index = (self.array as NSArray).index(of: objectAtZero)
Or If you want to found index on the basis of key from Dictionary. Here array contains Objects of Model class and I am matching id property.
let userId = 20
if let index = array.index(where: { (dict) -> Bool in
return dict.id == userId // Will found index of matched id
}) {
print("Index found")
}
OR
let storeId = Int(surveyCurrent.store_id) // Accessing model key value
indexArrUpTo = self.arrEarnUpTo.index { Int($0.store_id) == storeId }! // Array contains models and finding specific one
In Swift 4, if you are traversing through your DataModel array, make sure your data model conforms to Equatable Protocol , implement the lhs=rhs method , and only then you can use ".index(of" . For example
class Photo : Equatable{
var imageURL: URL?
init(imageURL: URL){
self.imageURL = imageURL
}
static func == (lhs: Photo, rhs: Photo) -> Bool{
return lhs.imageURL == rhs.imageURL
}
}
And then,
let index = self.photos.index(of: aPhoto)
For (>= swift 4.0)
It's rather very simple.
Consider the following Array object.
var names: [String] = ["jack", "rose", "jill"]
In order to obtain the index of the element rose, all you have to do is:
names.index(of: "rose") // returns 1
Note:
Array.index(of:) returns an Optional<Int>.
nil implies that the element isn't present in the array.
You might want to force-unwrap the returned value or use an if-let to get around the optional.
Swift 2.1
var array = ["0","1","2","3"]
if let index = array.indexOf("1") {
array.removeAtIndex(index)
}
print(array) // ["0","2","3"]
Swift 3
var array = ["0","1","2","3"]
if let index = array.index(of: "1") {
array.remove(at: index)
}
array.remove(at: 1)
In Swift 2 (with Xcode 7), Array includes an indexOf method provided by the CollectionType protocol. (Actually, two indexOf methods—one that uses equality to match an argument, and another that uses a closure.)
Prior to Swift 2, there wasn't a way for generic types like collections to provide methods for the concrete types derived from them (like arrays). So, in Swift 1.x, "index of" is a global function... And it got renamed, too, so in Swift 1.x, that global function is called find.
It's also possible (but not necessary) to use the indexOfObject method from NSArray... or any of the other, more sophisticated search meth dis from Foundation that don't have equivalents in the Swift standard library. Just import Foundation (or another module that transitively imports Foundation), cast your Array to NSArray, and you can use the many search methods on NSArray.
Any of this solution works for me
This the solution i have for Swift 4 :
let monday = Day(name: "M")
let tuesday = Day(name: "T")
let friday = Day(name: "F")
let days = [monday, tuesday, friday]
let index = days.index(where: {
//important to test with === to be sure it's the same object reference
$0 === tuesday
})
You can also use the functional library Dollar to do an indexOf on an array as such http://www.dollarswift.org/#indexof-indexof
$.indexOf([1, 2, 3, 1, 2, 3], value: 2)
=> 1
If you are still working in Swift 1.x
then try,
let testArray = ["A","B","C"]
let indexOfA = find(testArray, "A")
let indexOfB = find(testArray, "B")
let indexOfC = find(testArray, "C")
For SWIFT 3 you can use a simple function
func find(objecToFind: String?) -> Int? {
for i in 0...arrayName.count {
if arrayName[i] == objectToFind {
return i
}
}
return nil
}
This will give the number position, so you can use like
arrayName.remove(at: (find(objecToFind))!)
Hope to be useful
In Swift 4/5, use "firstIndex" for find index.
let index = array.firstIndex{$0 == value}
Swift 4
For reference types:
extension Array where Array.Element: AnyObject {
func index(ofElement element: Element) -> Int? {
for (currentIndex, currentElement) in self.enumerated() {
if currentElement === element {
return currentIndex
}
}
return nil
}
}
In case somebody has this problem
Cannot invoke initializer for type 'Int' with an argument list of type '(Array<Element>.Index?)'
jsut do this
extension Int {
var toInt: Int {
return self
}
}
then
guard let finalIndex = index?.toInt else {
return false
}
SWIFT 4
Let's say you want to store a number from the array called cardButtons into cardNumber, you can do it this way:
let cardNumber = cardButtons.index(of: sender)
sender is the name of your button

filter/identify dictionary keys that have matching values

Not sure if I need reduce, sorting, filtering or using the newer unique methods. I've even tried Equatable solutions.
I need to auto-identify keys that have matching values and take only those keys and put them into a new dictionary or array.
var userDB: [String:Any] = ["userID1":"gameIDa", "userID2":"gameIDa", "userID3":"gameIDc", "userID4":"gameIDd", "userID5":"gameIDe"]
As you can see only these two IDs have the same value of gameIDa. I need output of this result.
// [userID1, userID2]
Thanks
You can use Dictionary(grouping:by:) to achieve this easily and then reduce it to a dictionary which contains only entries with multiple values.
var userDB: [String: String] = ["userID1":"gameIDa", "userID2":"gameIDb", "userID3":"gameIDc", "userID4":"gameIDa", "userID5":"gameIDe"]
let dict = Dictionary(grouping: userDB.keys) { userDB[$0] ?? "" }.reduce(into: [String:[String]](), { (result, element) in
if element.value.count > 1 {
result[element.key] = element.value
}
})
dict
["gameIDa": ["userID1", "userID4"]]
Firstly, in order to be able to compare values, the Dictionary Value type needs to be an Equatable one. Once this is fulfilled, you can easily filter the keys that hold the queried value:
extension Dictionary where Value: Equatable {
func keysWithCommonValues() -> [Key] {
// go over all keys and keep ones for which the dictionary has one another key with the same value
return keys.filter { key in contains { $0.key != key && $0.value == self[key] } }
}
}
// userDB is not inferred as [String:String]
var userDB = ["userID1":"gameIDa", "userID2":"gameIDa", "userID3":"gameIDc", "userID4":"gameIDd", "userID5":"gameIDe"]
print(userDB.keysWithCommonValues()) // ["userID1", "userID2"]

What is the update for find() in Swift 3? [duplicate]

I am trying to find an item index by searching a list. Does anybody know how to do that?
I see there is list.StartIndex and list.EndIndex but I want something like python's list.index("text").
As swift is in some regards more functional than object-oriented (and Arrays are structs, not objects), use the function "find" to operate on the array, which returns an optional value, so be prepared to handle a nil value:
let arr:Array = ["a","b","c"]
find(arr, "c")! // 2
find(arr, "d") // nil
Use firstIndex and lastIndex - depending on whether you are looking for the first or last index of the item:
let arr = ["a","b","c","a"]
let indexOfA = arr.firstIndex(of: "a") // 0
let indexOfB = arr.lastIndex(of: "a") // 3
tl;dr:
For classes, you might be looking for:
let index = someArray.firstIndex{$0 === someObject}
Full answer:
I think it's worth mentioning that with reference types (class) you might want to perform an identity comparison, in which case you just need to use the === identity operator in the predicate closure:
Swift 5, Swift 4.2:
let person1 = Person(name: "John")
let person2 = Person(name: "Sue")
let person3 = Person(name: "Maria")
let person4 = Person(name: "Loner")
let people = [person1, person2, person3]
let indexOfPerson1 = people.firstIndex{$0 === person1} // 0
let indexOfPerson2 = people.firstIndex{$0 === person2} // 1
let indexOfPerson3 = people.firstIndex{$0 === person3} // 2
let indexOfPerson4 = people.firstIndex{$0 === person4} // nil
Note that the above syntax uses trailing closures syntax, and is equivalent to:
let indexOfPerson1 = people.firstIndex(where: {$0 === person1})
Swift 4 / Swift 3 - the function used to be called index
Swift 2 - the function used to be called indexOf
* Note the relevant and useful comment by paulbailey about class types that implement Equatable, where you need to consider whether you should be comparing using === (identity operator) or == (equality operator). If you decide to match using ==, then you can simply use the method suggested by others (people.firstIndex(of: person1)).
You can filter an array with a closure:
var myList = [1, 2, 3, 4]
var filtered = myList.filter { $0 == 3 } // <= returns [3]
And you can count an array:
filtered.count // <= returns 1
So you can determine if an array includes your element by combining these:
myList.filter { $0 == 3 }.count > 0 // <= returns true if the array includes 3
If you want to find the position, I don't see fancy way, but you can certainly do it like this:
var found: Int? // <= will hold the index if it was found, or else will be nil
for i in (0..x.count) {
if x[i] == 3 {
found = i
}
}
EDIT
While we're at it, for a fun exercise let's extend Array to have a find method:
extension Array {
func find(includedElement: T -> Bool) -> Int? {
for (idx, element) in enumerate(self) {
if includedElement(element) {
return idx
}
}
return nil
}
}
Now we can do this:
myList.find { $0 == 3 }
// returns the index position of 3 or nil if not found
Swift 5
func firstIndex(of element: Element) -> Int?
var alphabets = ["A", "B", "E", "D"]
Example1
let index = alphabets.firstIndex(where: {$0 == "A"})
Example2
if let i = alphabets.firstIndex(of: "E") {
alphabets[i] = "C" // i is the index
}
print(alphabets)
// Prints "["A", "B", "C", "D"]"
While indexOf() works perfectly, it only returns one index.
I was looking for an elegant way to get an array of indexes for elements which satisfy some condition.
Here is how it can be done:
Swift 3:
let array = ["apple", "dog", "log"]
let indexes = array.enumerated().filter {
$0.element.contains("og")
}.map{$0.offset}
print(indexes)
Swift 2:
let array = ["apple", "dog", "log"]
let indexes = array.enumerate().filter {
$0.element.containsString("og")
}.map{$0.index}
print(indexes)
in Swift 4.2
.index(where:) was changed to .firstIndex(where:)
array.firstIndex(where: {$0 == "person1"})
For custom class, you need to implement the Equatable protocol.
import Foundation
func ==(l: MyClass, r: MyClass) -> Bool {
return l.id == r.id
}
class MyClass: Equtable {
init(id: String) {
self.msgID = id
}
let msgID: String
}
let item = MyClass(3)
let itemList = [MyClass(1), MyClass(2), item]
let idx = itemList.indexOf(item)
printl(idx)
In Swift 4, the firstIndex method can be used. An example of using the == equality operator to find an object in an array by its id:
let index = array.firstIndex{ $0.id == object.id }
note this solution avoids your code needing to conform to the Equitable protocol as we're comparing the property and not the entire object
Also, a note about == vs === since many of the answers posted so far have differed in their usage:
== is the equality operator. It checks if values are equal.
=== is the identity operator. It checks whether two instances of a class point to the same memory. This is different from equality, because two objects that were created independently using the same values will be considered equal using == but not === because they are different objects. (Source)
It would be worth it to read more on these operators from Swift's documentation.
Just use firstIndex method.
array.firstIndex(where: { $0 == searchedItem })
Update for Swift 2:
sequence.contains(element): Returns true if a given sequence (such as
an array) contains the specified element.
Swift 1:
If you're looking just to check if an element is contained inside an array, that is, just get a boolean indicator, use contains(sequence, element) instead of find(array, element):
contains(sequence, element): Returns true if a given sequence (such as
an array) contains the specified element.
See example below:
var languages = ["Swift", "Objective-C"]
contains(languages, "Swift") == true
contains(languages, "Java") == false
contains([29, 85, 42, 96, 75], 42) == true
if (contains(languages, "Swift")) {
// Use contains in these cases, instead of find.
}
Swift 4. If your array contains elements of type [String: AnyObject]. So to find the index of element use the below code
var array = [[String: AnyObject]]()// Save your data in array
let objectAtZero = array[0] // get first object
let index = (self.array as NSArray).index(of: objectAtZero)
Or If you want to found index on the basis of key from Dictionary. Here array contains Objects of Model class and I am matching id property.
let userId = 20
if let index = array.index(where: { (dict) -> Bool in
return dict.id == userId // Will found index of matched id
}) {
print("Index found")
}
OR
let storeId = Int(surveyCurrent.store_id) // Accessing model key value
indexArrUpTo = self.arrEarnUpTo.index { Int($0.store_id) == storeId }! // Array contains models and finding specific one
In Swift 4, if you are traversing through your DataModel array, make sure your data model conforms to Equatable Protocol , implement the lhs=rhs method , and only then you can use ".index(of" . For example
class Photo : Equatable{
var imageURL: URL?
init(imageURL: URL){
self.imageURL = imageURL
}
static func == (lhs: Photo, rhs: Photo) -> Bool{
return lhs.imageURL == rhs.imageURL
}
}
And then,
let index = self.photos.index(of: aPhoto)
For (>= swift 4.0)
It's rather very simple.
Consider the following Array object.
var names: [String] = ["jack", "rose", "jill"]
In order to obtain the index of the element rose, all you have to do is:
names.index(of: "rose") // returns 1
Note:
Array.index(of:) returns an Optional<Int>.
nil implies that the element isn't present in the array.
You might want to force-unwrap the returned value or use an if-let to get around the optional.
Swift 2.1
var array = ["0","1","2","3"]
if let index = array.indexOf("1") {
array.removeAtIndex(index)
}
print(array) // ["0","2","3"]
Swift 3
var array = ["0","1","2","3"]
if let index = array.index(of: "1") {
array.remove(at: index)
}
array.remove(at: 1)
In Swift 2 (with Xcode 7), Array includes an indexOf method provided by the CollectionType protocol. (Actually, two indexOf methods—one that uses equality to match an argument, and another that uses a closure.)
Prior to Swift 2, there wasn't a way for generic types like collections to provide methods for the concrete types derived from them (like arrays). So, in Swift 1.x, "index of" is a global function... And it got renamed, too, so in Swift 1.x, that global function is called find.
It's also possible (but not necessary) to use the indexOfObject method from NSArray... or any of the other, more sophisticated search meth dis from Foundation that don't have equivalents in the Swift standard library. Just import Foundation (or another module that transitively imports Foundation), cast your Array to NSArray, and you can use the many search methods on NSArray.
Any of this solution works for me
This the solution i have for Swift 4 :
let monday = Day(name: "M")
let tuesday = Day(name: "T")
let friday = Day(name: "F")
let days = [monday, tuesday, friday]
let index = days.index(where: {
//important to test with === to be sure it's the same object reference
$0 === tuesday
})
You can also use the functional library Dollar to do an indexOf on an array as such http://www.dollarswift.org/#indexof-indexof
$.indexOf([1, 2, 3, 1, 2, 3], value: 2)
=> 1
If you are still working in Swift 1.x
then try,
let testArray = ["A","B","C"]
let indexOfA = find(testArray, "A")
let indexOfB = find(testArray, "B")
let indexOfC = find(testArray, "C")
For SWIFT 3 you can use a simple function
func find(objecToFind: String?) -> Int? {
for i in 0...arrayName.count {
if arrayName[i] == objectToFind {
return i
}
}
return nil
}
This will give the number position, so you can use like
arrayName.remove(at: (find(objecToFind))!)
Hope to be useful
In Swift 4/5, use "firstIndex" for find index.
let index = array.firstIndex{$0 == value}
Swift 4
For reference types:
extension Array where Array.Element: AnyObject {
func index(ofElement element: Element) -> Int? {
for (currentIndex, currentElement) in self.enumerated() {
if currentElement === element {
return currentIndex
}
}
return nil
}
}
In case somebody has this problem
Cannot invoke initializer for type 'Int' with an argument list of type '(Array<Element>.Index?)'
jsut do this
extension Int {
var toInt: Int {
return self
}
}
then
guard let finalIndex = index?.toInt else {
return false
}
SWIFT 4
Let's say you want to store a number from the array called cardButtons into cardNumber, you can do it this way:
let cardNumber = cardButtons.index(of: sender)
sender is the name of your button

".indexOf" an array of Custom Objects [duplicate]

I am trying to find an item index by searching a list. Does anybody know how to do that?
I see there is list.StartIndex and list.EndIndex but I want something like python's list.index("text").
As swift is in some regards more functional than object-oriented (and Arrays are structs, not objects), use the function "find" to operate on the array, which returns an optional value, so be prepared to handle a nil value:
let arr:Array = ["a","b","c"]
find(arr, "c")! // 2
find(arr, "d") // nil
Use firstIndex and lastIndex - depending on whether you are looking for the first or last index of the item:
let arr = ["a","b","c","a"]
let indexOfA = arr.firstIndex(of: "a") // 0
let indexOfB = arr.lastIndex(of: "a") // 3
tl;dr:
For classes, you might be looking for:
let index = someArray.firstIndex{$0 === someObject}
Full answer:
I think it's worth mentioning that with reference types (class) you might want to perform an identity comparison, in which case you just need to use the === identity operator in the predicate closure:
Swift 5, Swift 4.2:
let person1 = Person(name: "John")
let person2 = Person(name: "Sue")
let person3 = Person(name: "Maria")
let person4 = Person(name: "Loner")
let people = [person1, person2, person3]
let indexOfPerson1 = people.firstIndex{$0 === person1} // 0
let indexOfPerson2 = people.firstIndex{$0 === person2} // 1
let indexOfPerson3 = people.firstIndex{$0 === person3} // 2
let indexOfPerson4 = people.firstIndex{$0 === person4} // nil
Note that the above syntax uses trailing closures syntax, and is equivalent to:
let indexOfPerson1 = people.firstIndex(where: {$0 === person1})
Swift 4 / Swift 3 - the function used to be called index
Swift 2 - the function used to be called indexOf
* Note the relevant and useful comment by paulbailey about class types that implement Equatable, where you need to consider whether you should be comparing using === (identity operator) or == (equality operator). If you decide to match using ==, then you can simply use the method suggested by others (people.firstIndex(of: person1)).
You can filter an array with a closure:
var myList = [1, 2, 3, 4]
var filtered = myList.filter { $0 == 3 } // <= returns [3]
And you can count an array:
filtered.count // <= returns 1
So you can determine if an array includes your element by combining these:
myList.filter { $0 == 3 }.count > 0 // <= returns true if the array includes 3
If you want to find the position, I don't see fancy way, but you can certainly do it like this:
var found: Int? // <= will hold the index if it was found, or else will be nil
for i in (0..x.count) {
if x[i] == 3 {
found = i
}
}
EDIT
While we're at it, for a fun exercise let's extend Array to have a find method:
extension Array {
func find(includedElement: T -> Bool) -> Int? {
for (idx, element) in enumerate(self) {
if includedElement(element) {
return idx
}
}
return nil
}
}
Now we can do this:
myList.find { $0 == 3 }
// returns the index position of 3 or nil if not found
Swift 5
func firstIndex(of element: Element) -> Int?
var alphabets = ["A", "B", "E", "D"]
Example1
let index = alphabets.firstIndex(where: {$0 == "A"})
Example2
if let i = alphabets.firstIndex(of: "E") {
alphabets[i] = "C" // i is the index
}
print(alphabets)
// Prints "["A", "B", "C", "D"]"
While indexOf() works perfectly, it only returns one index.
I was looking for an elegant way to get an array of indexes for elements which satisfy some condition.
Here is how it can be done:
Swift 3:
let array = ["apple", "dog", "log"]
let indexes = array.enumerated().filter {
$0.element.contains("og")
}.map{$0.offset}
print(indexes)
Swift 2:
let array = ["apple", "dog", "log"]
let indexes = array.enumerate().filter {
$0.element.containsString("og")
}.map{$0.index}
print(indexes)
in Swift 4.2
.index(where:) was changed to .firstIndex(where:)
array.firstIndex(where: {$0 == "person1"})
For custom class, you need to implement the Equatable protocol.
import Foundation
func ==(l: MyClass, r: MyClass) -> Bool {
return l.id == r.id
}
class MyClass: Equtable {
init(id: String) {
self.msgID = id
}
let msgID: String
}
let item = MyClass(3)
let itemList = [MyClass(1), MyClass(2), item]
let idx = itemList.indexOf(item)
printl(idx)
In Swift 4, the firstIndex method can be used. An example of using the == equality operator to find an object in an array by its id:
let index = array.firstIndex{ $0.id == object.id }
note this solution avoids your code needing to conform to the Equitable protocol as we're comparing the property and not the entire object
Also, a note about == vs === since many of the answers posted so far have differed in their usage:
== is the equality operator. It checks if values are equal.
=== is the identity operator. It checks whether two instances of a class point to the same memory. This is different from equality, because two objects that were created independently using the same values will be considered equal using == but not === because they are different objects. (Source)
It would be worth it to read more on these operators from Swift's documentation.
Just use firstIndex method.
array.firstIndex(where: { $0 == searchedItem })
Update for Swift 2:
sequence.contains(element): Returns true if a given sequence (such as
an array) contains the specified element.
Swift 1:
If you're looking just to check if an element is contained inside an array, that is, just get a boolean indicator, use contains(sequence, element) instead of find(array, element):
contains(sequence, element): Returns true if a given sequence (such as
an array) contains the specified element.
See example below:
var languages = ["Swift", "Objective-C"]
contains(languages, "Swift") == true
contains(languages, "Java") == false
contains([29, 85, 42, 96, 75], 42) == true
if (contains(languages, "Swift")) {
// Use contains in these cases, instead of find.
}
Swift 4. If your array contains elements of type [String: AnyObject]. So to find the index of element use the below code
var array = [[String: AnyObject]]()// Save your data in array
let objectAtZero = array[0] // get first object
let index = (self.array as NSArray).index(of: objectAtZero)
Or If you want to found index on the basis of key from Dictionary. Here array contains Objects of Model class and I am matching id property.
let userId = 20
if let index = array.index(where: { (dict) -> Bool in
return dict.id == userId // Will found index of matched id
}) {
print("Index found")
}
OR
let storeId = Int(surveyCurrent.store_id) // Accessing model key value
indexArrUpTo = self.arrEarnUpTo.index { Int($0.store_id) == storeId }! // Array contains models and finding specific one
In Swift 4, if you are traversing through your DataModel array, make sure your data model conforms to Equatable Protocol , implement the lhs=rhs method , and only then you can use ".index(of" . For example
class Photo : Equatable{
var imageURL: URL?
init(imageURL: URL){
self.imageURL = imageURL
}
static func == (lhs: Photo, rhs: Photo) -> Bool{
return lhs.imageURL == rhs.imageURL
}
}
And then,
let index = self.photos.index(of: aPhoto)
For (>= swift 4.0)
It's rather very simple.
Consider the following Array object.
var names: [String] = ["jack", "rose", "jill"]
In order to obtain the index of the element rose, all you have to do is:
names.index(of: "rose") // returns 1
Note:
Array.index(of:) returns an Optional<Int>.
nil implies that the element isn't present in the array.
You might want to force-unwrap the returned value or use an if-let to get around the optional.
Swift 2.1
var array = ["0","1","2","3"]
if let index = array.indexOf("1") {
array.removeAtIndex(index)
}
print(array) // ["0","2","3"]
Swift 3
var array = ["0","1","2","3"]
if let index = array.index(of: "1") {
array.remove(at: index)
}
array.remove(at: 1)
In Swift 2 (with Xcode 7), Array includes an indexOf method provided by the CollectionType protocol. (Actually, two indexOf methods—one that uses equality to match an argument, and another that uses a closure.)
Prior to Swift 2, there wasn't a way for generic types like collections to provide methods for the concrete types derived from them (like arrays). So, in Swift 1.x, "index of" is a global function... And it got renamed, too, so in Swift 1.x, that global function is called find.
It's also possible (but not necessary) to use the indexOfObject method from NSArray... or any of the other, more sophisticated search meth dis from Foundation that don't have equivalents in the Swift standard library. Just import Foundation (or another module that transitively imports Foundation), cast your Array to NSArray, and you can use the many search methods on NSArray.
Any of this solution works for me
This the solution i have for Swift 4 :
let monday = Day(name: "M")
let tuesday = Day(name: "T")
let friday = Day(name: "F")
let days = [monday, tuesday, friday]
let index = days.index(where: {
//important to test with === to be sure it's the same object reference
$0 === tuesday
})
You can also use the functional library Dollar to do an indexOf on an array as such http://www.dollarswift.org/#indexof-indexof
$.indexOf([1, 2, 3, 1, 2, 3], value: 2)
=> 1
If you are still working in Swift 1.x
then try,
let testArray = ["A","B","C"]
let indexOfA = find(testArray, "A")
let indexOfB = find(testArray, "B")
let indexOfC = find(testArray, "C")
For SWIFT 3 you can use a simple function
func find(objecToFind: String?) -> Int? {
for i in 0...arrayName.count {
if arrayName[i] == objectToFind {
return i
}
}
return nil
}
This will give the number position, so you can use like
arrayName.remove(at: (find(objecToFind))!)
Hope to be useful
In Swift 4/5, use "firstIndex" for find index.
let index = array.firstIndex{$0 == value}
Swift 4
For reference types:
extension Array where Array.Element: AnyObject {
func index(ofElement element: Element) -> Int? {
for (currentIndex, currentElement) in self.enumerated() {
if currentElement === element {
return currentIndex
}
}
return nil
}
}
In case somebody has this problem
Cannot invoke initializer for type 'Int' with an argument list of type '(Array<Element>.Index?)'
jsut do this
extension Int {
var toInt: Int {
return self
}
}
then
guard let finalIndex = index?.toInt else {
return false
}
SWIFT 4
Let's say you want to store a number from the array called cardButtons into cardNumber, you can do it this way:
let cardNumber = cardButtons.index(of: sender)
sender is the name of your button

How to find index of list item in Swift?

I am trying to find an item index by searching a list. Does anybody know how to do that?
I see there is list.StartIndex and list.EndIndex but I want something like python's list.index("text").
As swift is in some regards more functional than object-oriented (and Arrays are structs, not objects), use the function "find" to operate on the array, which returns an optional value, so be prepared to handle a nil value:
let arr:Array = ["a","b","c"]
find(arr, "c")! // 2
find(arr, "d") // nil
Use firstIndex and lastIndex - depending on whether you are looking for the first or last index of the item:
let arr = ["a","b","c","a"]
let indexOfA = arr.firstIndex(of: "a") // 0
let indexOfB = arr.lastIndex(of: "a") // 3
tl;dr:
For classes, you might be looking for:
let index = someArray.firstIndex{$0 === someObject}
Full answer:
I think it's worth mentioning that with reference types (class) you might want to perform an identity comparison, in which case you just need to use the === identity operator in the predicate closure:
Swift 5, Swift 4.2:
let person1 = Person(name: "John")
let person2 = Person(name: "Sue")
let person3 = Person(name: "Maria")
let person4 = Person(name: "Loner")
let people = [person1, person2, person3]
let indexOfPerson1 = people.firstIndex{$0 === person1} // 0
let indexOfPerson2 = people.firstIndex{$0 === person2} // 1
let indexOfPerson3 = people.firstIndex{$0 === person3} // 2
let indexOfPerson4 = people.firstIndex{$0 === person4} // nil
Note that the above syntax uses trailing closures syntax, and is equivalent to:
let indexOfPerson1 = people.firstIndex(where: {$0 === person1})
Swift 4 / Swift 3 - the function used to be called index
Swift 2 - the function used to be called indexOf
* Note the relevant and useful comment by paulbailey about class types that implement Equatable, where you need to consider whether you should be comparing using === (identity operator) or == (equality operator). If you decide to match using ==, then you can simply use the method suggested by others (people.firstIndex(of: person1)).
You can filter an array with a closure:
var myList = [1, 2, 3, 4]
var filtered = myList.filter { $0 == 3 } // <= returns [3]
And you can count an array:
filtered.count // <= returns 1
So you can determine if an array includes your element by combining these:
myList.filter { $0 == 3 }.count > 0 // <= returns true if the array includes 3
If you want to find the position, I don't see fancy way, but you can certainly do it like this:
var found: Int? // <= will hold the index if it was found, or else will be nil
for i in (0..x.count) {
if x[i] == 3 {
found = i
}
}
EDIT
While we're at it, for a fun exercise let's extend Array to have a find method:
extension Array {
func find(includedElement: T -> Bool) -> Int? {
for (idx, element) in enumerate(self) {
if includedElement(element) {
return idx
}
}
return nil
}
}
Now we can do this:
myList.find { $0 == 3 }
// returns the index position of 3 or nil if not found
Swift 5
func firstIndex(of element: Element) -> Int?
var alphabets = ["A", "B", "E", "D"]
Example1
let index = alphabets.firstIndex(where: {$0 == "A"})
Example2
if let i = alphabets.firstIndex(of: "E") {
alphabets[i] = "C" // i is the index
}
print(alphabets)
// Prints "["A", "B", "C", "D"]"
While indexOf() works perfectly, it only returns one index.
I was looking for an elegant way to get an array of indexes for elements which satisfy some condition.
Here is how it can be done:
Swift 3:
let array = ["apple", "dog", "log"]
let indexes = array.enumerated().filter {
$0.element.contains("og")
}.map{$0.offset}
print(indexes)
Swift 2:
let array = ["apple", "dog", "log"]
let indexes = array.enumerate().filter {
$0.element.containsString("og")
}.map{$0.index}
print(indexes)
in Swift 4.2
.index(where:) was changed to .firstIndex(where:)
array.firstIndex(where: {$0 == "person1"})
For custom class, you need to implement the Equatable protocol.
import Foundation
func ==(l: MyClass, r: MyClass) -> Bool {
return l.id == r.id
}
class MyClass: Equtable {
init(id: String) {
self.msgID = id
}
let msgID: String
}
let item = MyClass(3)
let itemList = [MyClass(1), MyClass(2), item]
let idx = itemList.indexOf(item)
printl(idx)
In Swift 4, the firstIndex method can be used. An example of using the == equality operator to find an object in an array by its id:
let index = array.firstIndex{ $0.id == object.id }
note this solution avoids your code needing to conform to the Equitable protocol as we're comparing the property and not the entire object
Also, a note about == vs === since many of the answers posted so far have differed in their usage:
== is the equality operator. It checks if values are equal.
=== is the identity operator. It checks whether two instances of a class point to the same memory. This is different from equality, because two objects that were created independently using the same values will be considered equal using == but not === because they are different objects. (Source)
It would be worth it to read more on these operators from Swift's documentation.
Just use firstIndex method.
array.firstIndex(where: { $0 == searchedItem })
Update for Swift 2:
sequence.contains(element): Returns true if a given sequence (such as
an array) contains the specified element.
Swift 1:
If you're looking just to check if an element is contained inside an array, that is, just get a boolean indicator, use contains(sequence, element) instead of find(array, element):
contains(sequence, element): Returns true if a given sequence (such as
an array) contains the specified element.
See example below:
var languages = ["Swift", "Objective-C"]
contains(languages, "Swift") == true
contains(languages, "Java") == false
contains([29, 85, 42, 96, 75], 42) == true
if (contains(languages, "Swift")) {
// Use contains in these cases, instead of find.
}
Swift 4. If your array contains elements of type [String: AnyObject]. So to find the index of element use the below code
var array = [[String: AnyObject]]()// Save your data in array
let objectAtZero = array[0] // get first object
let index = (self.array as NSArray).index(of: objectAtZero)
Or If you want to found index on the basis of key from Dictionary. Here array contains Objects of Model class and I am matching id property.
let userId = 20
if let index = array.index(where: { (dict) -> Bool in
return dict.id == userId // Will found index of matched id
}) {
print("Index found")
}
OR
let storeId = Int(surveyCurrent.store_id) // Accessing model key value
indexArrUpTo = self.arrEarnUpTo.index { Int($0.store_id) == storeId }! // Array contains models and finding specific one
In Swift 4, if you are traversing through your DataModel array, make sure your data model conforms to Equatable Protocol , implement the lhs=rhs method , and only then you can use ".index(of" . For example
class Photo : Equatable{
var imageURL: URL?
init(imageURL: URL){
self.imageURL = imageURL
}
static func == (lhs: Photo, rhs: Photo) -> Bool{
return lhs.imageURL == rhs.imageURL
}
}
And then,
let index = self.photos.index(of: aPhoto)
For (>= swift 4.0)
It's rather very simple.
Consider the following Array object.
var names: [String] = ["jack", "rose", "jill"]
In order to obtain the index of the element rose, all you have to do is:
names.index(of: "rose") // returns 1
Note:
Array.index(of:) returns an Optional<Int>.
nil implies that the element isn't present in the array.
You might want to force-unwrap the returned value or use an if-let to get around the optional.
Swift 2.1
var array = ["0","1","2","3"]
if let index = array.indexOf("1") {
array.removeAtIndex(index)
}
print(array) // ["0","2","3"]
Swift 3
var array = ["0","1","2","3"]
if let index = array.index(of: "1") {
array.remove(at: index)
}
array.remove(at: 1)
In Swift 2 (with Xcode 7), Array includes an indexOf method provided by the CollectionType protocol. (Actually, two indexOf methods—one that uses equality to match an argument, and another that uses a closure.)
Prior to Swift 2, there wasn't a way for generic types like collections to provide methods for the concrete types derived from them (like arrays). So, in Swift 1.x, "index of" is a global function... And it got renamed, too, so in Swift 1.x, that global function is called find.
It's also possible (but not necessary) to use the indexOfObject method from NSArray... or any of the other, more sophisticated search meth dis from Foundation that don't have equivalents in the Swift standard library. Just import Foundation (or another module that transitively imports Foundation), cast your Array to NSArray, and you can use the many search methods on NSArray.
Any of this solution works for me
This the solution i have for Swift 4 :
let monday = Day(name: "M")
let tuesday = Day(name: "T")
let friday = Day(name: "F")
let days = [monday, tuesday, friday]
let index = days.index(where: {
//important to test with === to be sure it's the same object reference
$0 === tuesday
})
You can also use the functional library Dollar to do an indexOf on an array as such http://www.dollarswift.org/#indexof-indexof
$.indexOf([1, 2, 3, 1, 2, 3], value: 2)
=> 1
If you are still working in Swift 1.x
then try,
let testArray = ["A","B","C"]
let indexOfA = find(testArray, "A")
let indexOfB = find(testArray, "B")
let indexOfC = find(testArray, "C")
For SWIFT 3 you can use a simple function
func find(objecToFind: String?) -> Int? {
for i in 0...arrayName.count {
if arrayName[i] == objectToFind {
return i
}
}
return nil
}
This will give the number position, so you can use like
arrayName.remove(at: (find(objecToFind))!)
Hope to be useful
In Swift 4/5, use "firstIndex" for find index.
let index = array.firstIndex{$0 == value}
Swift 4
For reference types:
extension Array where Array.Element: AnyObject {
func index(ofElement element: Element) -> Int? {
for (currentIndex, currentElement) in self.enumerated() {
if currentElement === element {
return currentIndex
}
}
return nil
}
}
In case somebody has this problem
Cannot invoke initializer for type 'Int' with an argument list of type '(Array<Element>.Index?)'
jsut do this
extension Int {
var toInt: Int {
return self
}
}
then
guard let finalIndex = index?.toInt else {
return false
}
SWIFT 4
Let's say you want to store a number from the array called cardButtons into cardNumber, you can do it this way:
let cardNumber = cardButtons.index(of: sender)
sender is the name of your button

Resources