Finding value in array containing custom class - arrays

I'm trying to find the place of a value in a an array containing structures.
My array looks like this
struct User {
var firstName: String?
var lastName: String?
}
var allThePeople = [User(firstName: "John", lastName: "Doe"), User(firstName: "Jane", lastName: "Doe"), User(firstName: "John", lastName: "Travolta")];
Is there a way to get the places for all "Doe"'s in the array? (in this case 0 and 1)

You can filter allThePeople with a condition to get all the people with the last name "Doe".
let allTheDoes = allThePeople.filter { $0.lastName == "Doe" }
You can enumerate the array and flat map it to an array of indices.
let allTheDoeIndexes = allThePeople.enumerated().flatMap { $0.element.lastName == "Doe" ? $0.offset : nil }
= allThePeople.enumerated().flatMap { $1.lastName == "Doe" ? $0 : nil }

If you want the actual indices, use something like
struct User {
var firstName: String?
var lastName: String?
}
var allThePeople = [User(firstName: "John", lastName: "Doe"), User(firstName: "Jane", lastName: "Doe"), User(firstName: "John", lastName: "Travolta")]
var indices = [Int]()
for i in 0 ..< allThePeople.count {
if allThePeople[i].lastName == "Doe" {
indices.append(i)
}
}
indices // [0,1]
otherwise use filter as #Callam suggested.

Related

How do i add objects into an array from a Class in Swift?

This is my Friend class:
class Friend {
var firstName: String = ""
var lastName: String = ""
var age: Int = 0
var description:String = ""
init(firstname: String, lastname: String, age: Int) {
self.firstName = firstname
self.lastName = lastname
self.age = age
}
}
This is where i'm supposed to declare and instantiate 5 Friend objects in the viewDidLoad function and to add them into 'friendList' array.
import UIKit
class ViewController: UIViewController {
var friendsList: [Friend] = []
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
friendsList.append("John", "Doe", 20)
}
}
Swift tells me that "No exact matches in call to instance method 'append'" on the "friendsList.append" line.
you can use like Below if you are creating all friends Initially
let friends = [Friend(firstname: "John", lastname: "Doe", age: 20),Friend(firstname: "doe", lastname: "John", age: 21)]
for friend in friends{
friendsList.append(friend)
}
//////////////////////////////////////
(or) you can directly declare value for your global variable
friendsList = [Friend(firstname: "John", lastname: "Doe", age: 20),Friend(firstname: "doe", lastname: "John", age: 21)]
///////////////////////////////////////////
(or) assign local variable value to your global variable
friendsList = friends
or if you adding One by One,You have to create object first
let friendOne = Friend(firstname: "John", lastname: "Doe", age: 20)
friendsList.append(friendOne)
The Array (Actually collection) function append takes a parameter of type <T> where T is a generic type, "the type of the elements in the array".
So if you have an array of Strings, you need to pass a String into append:
var strings = [String]()
strings.append("a string")
Since you have an array of Friend objects, you need to pass an instance of Friend to the append(_:) function. Does the expression inside the parentheses in your call to append evaluate to a friend object?
friendsList.append("John", "Doe", 20)
It doesn't. You'r passing a comma-separated list of properties. Presumably, those are the first name, last name, and age of a Friend, but the append() function doesn't know that.
You could write it as:
let aFriend = Friend(firstname: "John", lastname: "Doe", age: 20)
friendList.append(aFriend)
Or all in one line with:
friendList.append(Friend(firstname: "John", lastname: "Doe", age: 20))
Both of those variations would work.

Swift - Check if a value belongs is in an array

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" }

Creating an array of struct without duplicates

Recently started learning Swift and is now faced with the problem (code below will insert):
I create an array of structure from 3 arrays. When creating an instance of the structure, I need to do it by random (randomElement as I understood) - all 3 parameters must be unique. How do I check for uniqueness in the function?
arrayOfHumans = createRandomHuman()
struct Human {
let name: String
let surname: String
let age: String
var email: String
}
var arrayOfHumans = [Human] ()
var humans: [Human] = []
let nameA = ["Tim", "Mike", "Stan"]
let surnameA = ["Burk", "Sims", "Stoch"]
let ageA = ["12", "30", "25"]
let emailA = ["one#live.com", "two#gmail.com", "three#outlook.com"]
func createRandomHuman() -> [Human] {
for _ in 1...3 {
if nameA.isEmpty == false {
let human = Human(name: nameA.randomElement()!,
surname: surnameA.randomElement()!,
age: ageA.randomElement()!,
email: emailA.randomElement()!)
humans.append(human)
}
}
return humans
}
Actual result:
first Struct {
name: Tim
surname: Sims
age: 12
email: three#outlook.com
}
second Struct {
name: Mike
surname: Stoch
age: 25
email: one#live.com
}
third Struct {
name: Stan
surname: Burk
age: 30
email: two#gmail.com
}
A solution is to shuffle the surname, age and email arrays separately to get a random but unique order.
let nameA = ["Tim", "Mike", "Stan"]
let surnameA = ["Burk", "Sims", "Stoch"]
let ageA = ["12", "30", "25"]
let emailA = ["one#live.com", "two#gmail.com", "three#outlook.com"]
func createRandomHuman() -> [Human] {
let shuffledSurnameA = surnameA.shuffled()
let shuffledAgeA = ageA.shuffled()
let shuffledEmailA = emailA.shuffled()
var humans: [Human] = []
for i in 0..<nameA.count {
let human = Human(name: nameA[i],
surname: shuffledSurnameA[i],
age: shuffledAgeA[i],
email: shuffledEmailA[i])
humans.append(human)
}
return humans
}
let arrayOfHumans = createRandomHuman()
Another way is to shuffle the indices
func createRandomHuman() -> [Human] {
let indices = nameA.indices
let shuffledIndices = (0..<3).map{ _ in indices.shuffled()}
var humans: [Human] = []
for i in 0..<nameA.count {
let human = Human(name: nameA[i],
surname: surnameA[shuffledIndices[0][i]],
age: ageA[shuffledIndices[1][i]],
email: emailA[shuffledIndices[2][i]])
humans.append(human)
}
return humans
}
If I understand you right, you want to ensure that all randomly created humans are different.
If so, the question is when are 2 humans different. This depends on your problem. Thus you as the programmer have to define it.
You can do it by adopting the Equatable protocol.
As soon as your structs conform to this protocol, you can loop through all previously initiated humans, and check if the new randomly created one is equal to one of them. If so, create a new one.

Swift - Grouping elements according to their equal features

In Swift 4, I have:
let customers = [Customer(name: "John", country: "US", profession: "Engineer"), Customer(name: "Mary", country: "UK", profession: "Nurse"), Customer(name: "Diana", country: "US", profession: "Engineer"), Customer(name: "Paul", country: "US", profession: "Plumber"), Customer(name: "Sam", country: "UK", profession: "Nurse")]
I would like to have for example a function that could filter the elements in customers, so that each time the names and professions of at least 2 elements in it are equal, they are added to an array automatically created by this function :
var customers1 = [Customer(name: "John", country: "US", profession: "Engineer"), Customer(name: "Diana", country: "US", profession: "Engineer")]
var customers2 = [Customer(name: "Mary", country: "UK", profession: "Nurse"), Customer(name: "Sam", country: "UK", profession: "Nurse")]
I searched without success, however I picked some solutions that perhaps could be adapted to this case:
extension Array where Element: Comparable {
func containsSameElements(as other: [Element]) -> Bool {
return self[1] == other[1] && self[2] == other[2]
}
}
or
func ==<Element : Equatable> (lhs: [[Element]], rhs: [[Element]]) -> Bool {
return lhs.elementsEqual(rhs, by: ==)
}
or
elementsEqual()/contains() with a loop.
or
a combination of flatMap()/reduce()/filter().
Thank you.
Based on your feedback and clarification, I would do something like this.
struct CountryAndProfession: Hashable, CustomStringConvertible {
let country: String
let profession: String
var description: String {
return "CountryAndProfession{country: \(country), profession: \(profession)}"
}
var hashValue: Int {
return "\(country)__\(profession)".hashValue
}
static func ==(left: CountryAndProfession, right: CountryAndProfession) -> Bool {
return left.country == right.country && left.profession == right.profession
}
}
// The Customer Type you apparently are dealing with. (May need a custom init depending on your use case
struct Customer: CustomStringConvertible {
let name: String
let countryAndProfession: CountryAndProfession
var description: String {
return "Customer{name: \(name), countryAndProfession: \(countryAndProfession)}"
}
// returns a dictionary with the passed customer's CountryAndProfession as the key, and the matching
static func makeDictionaryWithCountryAndProfession(from customers: [Customer]) -> [CountryAndProfession : [Customer]] {
var customersArrayDictionary: [CountryAndProfession : [Customer]] = [:]
customers.forEach { (customer) in
if customersArrayDictionary.keys.contains(customer.countryAndProfession) {
customersArrayDictionary[customer.countryAndProfession]?.append(customer)
}
else {
customersArrayDictionary[customer.countryAndProfession] = [customer]
}
}
return customersArrayDictionary
}
static func getArraysBasedOnCountries(from customerArray: [Customer]) -> [[Customer]] {
return Array(makeDictionaryWithCountryAndProfession(from: customerArray).values)
}
}
let arrayOfArrays = [["John", "A", "A" ], ["Mary", "A", "B" ], ["Diana", "A", "A" ], ["Paul", "B", "B" ], ["Sam", "A", "B" ]]
//If you're dealing with non-predictable data, you should probably have some Optionality
let allCustomers = arrayOfArrays.map{ Customer(name: $0[0], countryAndProfession: CountryAndProfession(country: $0[1], profession: $0[2])) }
let splitCustomers = Customer.getArraysBasedOnCountries(from: allCustomers)
//contains [[John, Diana], [Mary, Sam], [Paul]]
I'm still not quite sure what you want your final result to look like (something that is always helpful to put in the question), but you should be able to get the result you're looking for using makeDictionaryWithCountryAndProfession combined with the specific CountryAndProfession you're looking for or using .filter
This is how I would recommend doing what you're trying to do:
struct Customer {
let name: String
let country: String
let profession: String
func countryMatches(with otherCustomer: Customer) -> Bool {
return country == otherCustomer.country
}
func professionMatches(with otherCustomer: Customer) -> Bool {
return profession == otherCustomer.profession
}
func countryAndProfessionMatch(with otherCustomer: Customer) -> Bool {
return countryMatches(with: otherCustomer) && professionMatches(with: otherCustomer)
}
static func getAllCustomersWithProfessionsAndCountriesMatching(with customer: Customer, from allCustomers: [Customer]) -> [Customer] {
return allCustomers.filter { customer.countryAndProfessionMatch(with: $0) }
}
}
let arrayOfArrays = [["John", "A", "A" ], ["Mary", "A", "B" ], ["Diana", "A", "A" ], ["Paul", "B", "B" ], ["Sam", "A", "B" ]]
//If you're dealing with non-predictable data, you should probably have some Optionality
let allCustomers = arrayOfArrays.map{ Customer(name: $0[0], country: $0[1], profession: $0[2]) }
let allCustomersMatchingJohnProperties = Customer.getAllCustomersWithProfessionsAndCountriesMatching(with: allCustomers[0], from: allCustomers)
// contains John and Diane
let allCustomersMatchingMaryProperties = Customer.getAllCustomersWithProfessionsAndCountriesMatching(with: allCustomers[1], from: allCustomers)
// contains Mary and Sam
I believe this does what you're looking to do, but with a more structured/maintainable approach.
getAllCustomersWithProfessionsAndCountriesMatching is almost definitely way too long, but left it that way to be clear for the answer. I would advice renaming it to fit your use case.

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