Swift - Check if a value belongs is in an array - arrays

I have an array of type "User" and I would like to check if a value belongs to a property type.
My code :
struct User: Identifiable {
var id = UUID()
var name: String
var age: String
}
var array: User = [
User[name: "AZE", age: "10"]
User[name: "QSD", age: "37"]
]
For example I'd like to know if "AZE" belongs to the property array "name". What is the function for retrieving this information. I hope you understood my problem and thank you for your answer.

First of all, arrays define with [Type] like [User]
Second of all init method calls as with (Arguments) like User(name: ,age:)
And last but not least, don't forget the ',' between elements of the array.
So
struct User: Identifiable {
var id = UUID()
var name: String
var age: String
}
var array: [User] = [
User(name: "AZE", age: "10"),
User(name: "QSD", age: "37")
]
So now you can check your element inside with contains like
array.contains(where: { user in user.name == "AZE" }) // returns `true` if it is
Tips
Try name arrays not array. Use plural names instead like users
To returtning the found one:
users.first(where: { user in user.name == "AZE" })
To summarizing it
users.first { $0.name == "AZE" }

Related

Group array by more than one property swift

Swift provides a method that converts array to dictionary on the basis of single property. Is it possible to group array to dictionary on the basis of more than one property. Something like following
For example we have array of objects containing name, age and gender
Person{
let name: String
let age: Int
let gender: String
}
And we have array containing persons
let array:[Person] = [Person(name: "Alex", age: 25, gender: "Male"), Person(name: "Sara", age: 25, gender: "Female")]
How can I group by multiple properties like name and age ?
Dictionary(grouping: array, by: { $0.name && $0.age })
You can group by anything that can become a key, in other words, by anything that is Hashable.
If you need to combine multiple properties, define a new type:
struct GroupingKey: Hashable {
let name: String
let age: Int
}
Dictionary(grouping: array, by: { GroupingKey(name: $0.name, age: $0.age) })

Search a dictionary in a custom object inside an array

I’m building search functionality. I have an array of User objects and each User has a dictionary of tags. I’m trying to return users with searched tags.
My user class is:
class User: NSObject {
var name: String?
var tags = Dictionary<String, String>()
}
An example of the tags is:
tags: {
“entry1” : “test1”,
“entry2” : “test2”,
“entry3” : “test3”
}
I’ve been trying variances of:
let predicate = NSPredicate(format: “tags contains[c] %#", “test1”);
let filteredArray = self.usersArray!.filter { predicate.evaluate(with: $0) }; print(“users = ,\(filteredArray)");
It’s throwing “this class is not key value coding-compliant for the key tags.’ I'm not sure how to search inside the User object.
Update:
I've change the dictionary to an array and
filter { $0.tags.contains(searchTerm) } works for exact search match, as suggested.
.filter( {$0.tags.reduce(false, {$1.contains(searchTerm)} )} ) does not work for a partial match however, which is what i'm looking for.
Here is what is printed:
Search term: ale
Result: []
Tags array inside each object:
["Alex", "Will", ""]
["Bob", "Dan", ""]
["First", "Second", "Third"]
["Testing 1", "Testing 2", ""]
Your implementation of tags seems cumbersome. Here is a simpler one.
class User {
var name: String
var tags: [String]
}
Now let's say you have an array of users in users.
var users: [User]
// Store users in the array
Now, this is how you check which user contains a particular tag.
let tag = "yourTag"
users.filter( { $0.tags.contains(tag) } )
However, if you are adamant that you need the tags in a dictionary, then you could do it like this,
users.filter( {$0.tags.values.contains(tag)} )
If you want to check if the tag is part of any of the tags in a particular user, you could do it like this,
let filteredUsers = users.filter( {$0.tags.reduce(false, {$1.contains(tag)} )} )
P.S - we don't use ; in Swift.
It's good practice to make your models conform to Codeable:
struct User: Codable {
var userId: UUID
var name: String = ""
var referenceTags: [String: String] = [:]
}
// Create some users:
let Bob = User(userId: UUID(), name: "Bob", referenceTags: ["tag1": "no", "tag2": "yes"])
let Steve = User(userId: UUID(), name: "Steve", referenceTags: ["tag2": "no", "tag3": "no"])
Create an array of users to filter.
let users:[User] = [Bob, Steve]
Get a search predicate or string from your Search bar or other.
let searchPredicate = "yes"
Filter and iterate over tags for the required value.
let results = users.filter { (user) -> Bool in
for (key, _) in user.referenceTags.enumerated() {
if (user.referenceTags[key] == searchPredicate) {
return true
}
}
}

Sort array of dictionaries where key is unknown

I have an array of dictionaries of type [[String:SchoolModel]]. The keys are the id of the school and then the school model contains info about the school like its name for example. I want to sort this array by SchoolModel.name, but can't figure out how since my key is a unique id for every element in the array.
struct SchoolModel {
var name: String
var city: String
var state: String
}
You can access the first value of each dictionary iterated to get the name.
struct SchoolModel {
var name: String
var city: String
var state: String
}
let schools: [[String:SchoolModel]] = [
["1": SchoolModel(name: "1", city: "a", state: "x")],
["2": SchoolModel(name: "2", city: "b", state: "y")],
["3": SchoolModel(name: "3", city: "c", state: "z")]
]
print(schools.sorted {
guard
let a = $0.values.first?.name,
let b = $1.values.first?.name else { return false }
return a < b
})
However, you should consider adding an id property to your struct. You can make it optional so you can still initiate a SchoolModel that hasn't been created yet.
struct SchoolModel {
var id: String?
var name: String
var city: String
var state: String
}
Then where ever you are populating the array of dictionaries, append the SchoolModel object without embedding it inside a dictionary, resulting in an array of type [SchoolModel].

How to sort Dictionary by keys where values are array of objects in Swift 4?

I have Dictionary which contains String keys and Array of Objects as value. These values are added from the sorted Array of objects into Dictionary using append method. The values are categorized into keys based on the first letter of object property. But returns unsorted Dictionary.
The dictionaries are declared:
var namesDic = [String: [Name]]()
var filteredNames = [String: [Name]]()
And iterating through array and appending into Dictionary:
for name in names {
let letterIndex = name.getName().index(name.getName().startIndex, offsetBy: 0)
let letter = name.getName()[letterIndex]
if namesDic[String(letter)] != nil {
namesDic[String(letter)]?.append(name)
} else {
namesDic[String(letter)] = [name]
}
}
filteredNames = namesDic
}
Name structure:
struct Name {
var id: Int!
var name: String!
var native: String!
var meaning: String!
var origin: String!
var isFavorite: Bool
var gender: String!
init(id: Int, name: String, native: String, meaning: String, origin: String, isFavorite: Int, gender: String) {
self.id = id
self.name = name
self.native = native
self.meaning = meaning
self.origin = origin
if isFavorite == 0 {
self.isFavorite = false
} else { self.isFavorite = true }
self.gender = gender
}
}
I found in debugging that they are unsorted when they are appended to dictionary. I understand sort on Swift Dictionary is not working but I want a work around to sort Dictionary by key to pass it to TableView.
I went through many questions/answers here but they are all for [String: String] not Array of Objects.
struct Name: CustomStringConvertible {
let id: Int
let name: String
let native: String
let meaning: String
let origin: String
let isFavorite: Bool
let gender: String
var description: String {
return "Id: " + String(id) + " - Name: " + name
}
}
let name1 = Name(id: 1, name: "Tim Cook", native: "native", meaning: "meaning", origin: "origin", isFavorite: true, gender: "Male")
let name2 = Name(id: 2, name: "Steve Jobs", native: "native", meaning: "meaning", origin: "origin", isFavorite: true, gender: "Male")
let name3 = Name(id: 3, name: "Tiger Woods", native: "native", meaning: "meaning", origin: "origin", isFavorite: true, gender: "Male")
let name4 = Name(id: 4, name: "Socrates", native: "native", meaning: "meaning", origin: "origin", isFavorite: true, gender: "Male")
let names = [name1, name2, name3, name4]
let dictionary = names.sorted(by: {$0.name < $1.name }).reduce(into: [String: [Name]]()) { result, element in
// make sure there is at least one letter in your string else return
guard let first = element.name.first else { return }
// create a string with that initial
let initial = String(first)
// initialize an array with one element or add another element to the existing value
result[initial, default: []].append(element)
}
let sorted = dictionary.sorted {$0.key < $1.key}
print(sorted) // "[(key: "S", value: [Id: 4 - Name: Socrates, Id: 2 - Name: Steve Jobs]), (key: "T", value: [Id: 3 - Name: Tiger Woods, Id: 1 - Name: Tim Cook])]\n"
According to Apple's documentation
A dictionary stores associations between keys of the same type and
values of the same type in a collection with no defined ordering. Each
value is associated with a unique key, which acts as an identifier for
that value within the dictionary. Unlike items in an array, items in
a dictionary do not have a specified order. You use a dictionary
when you need to look up values based on their identifier, in much the
same way that a real-world dictionary is used to look up the
definition for a particular word.
Further information is available on Apple's Website
Workaround
One thing that could be done is to create an array of sorted keys and then use that array to access the dictionary values

How to print variables in structs in arrays?

With this Swift 3.0 lines:
struct Person {
var name: String
var surname: String
var phone: Int
var isCustomer: Bool
}
var contacts: [Person] = []
contacts.append(Person(name: "Jack", surname: "Johnson", phone: 2, isCustomer: false))
contacts.append(Person(name: "Mike", surname: "Morris", phone: 3, isCustomer: true))
I have created an array that includes two structures which include 4 variables each.
I can print a single object of the array like this: print(contacts[0].name)
but is there any way to print all the Strings of the name section at once?
Learn how to use map. I use it all the time.
print(contacts.map({ $0.name }))
Search for map in this Apple Documentation about Closures
You'll have to iterate over the array, either printing the values as you go, or capturing them into a string and printing them all at once.
Here's one way:
for contact in contacts {
print(contact.name)
}
Here's another:
contacts.forEach { print($0.name) }
Finally, you could join all the strings into one value with a separator and just print once. When you do it this way the joinWithSeparator function iterates the array for you:
let names = contacts.map { $0.name }
let joinedNames = names.joinWithSeparator(" ")
print(joinedNames)
You should implement the protocol CustomStringConvertible by defining the computed property description:
struct Person: CustomStringConvertible {
var name: String
var surname: String
var phone: Int
var isCustomer: Bool
var description: String {
return
"Name: \(name)\n" +
"Surname: \(surname)\n" +
"Phone: \(phone)\n" +
"Is Customer? \(isCustomer)\n"
}
}
And then:
var contacts: [Person] = []
contacts.append(Person(name: "Jack", surname: "Johnson", phone: 2, isCustomer: false))
contacts.append(Person(name: "Mike", surname: "Morris", phone: 3, isCustomer: true))
print(contacts)
Obviously you can define description as you want.

Resources