Array of struct in Swift - swift

Iteration of elements yield error
could not find member 'convertFromStringInterpolationSegment'
println("\(contacts[count].name)")", while direct list item prints fine.
What am I missing?
struct Person {
var name: String
var surname: String
var phone: String
var isCustomer: Bool
init(name: String, surname: String, phone: String, isCustomer: Bool)
{
self.name = name
self.surname = surname
self.phone = phone
self.isCustomer = isCustomer
}
}
var contacts: [Person] = []
var person1: Person = Person(name: "Jack", surname: "Johnson", phone: "7827493", isCustomer: false)
contacts.append(person1)
var count: Int = 0
for count in contacts {
println("\(contacts[count].name)") // here's where I get an error
}
println(contacts[0].name) // prints just fine - "Jack"

The for-in loop iterates over a collection of items, and provides the actual item and not its index at each iteration. So your loop should be rewritten as:
for contact in contacts {
println("\(contact.name)") // here's where I get an error
}
Note that this line:
var count: Int = 0
has no effect in your code, because the count variable in the for-in is redefined and visible to the block of code nested inside the loop.
If you still want to play with indexes, then you have to modify your loop as:
for var count = 0; count < contacts.count; ++count {
or
for count in 0..<contacts.count {
Last, if you need both the index and the value, maybe the easiest way is through the enumerate global function, which returns a list of (index, value) tuples:
for (index, contact) in enumerate(contacts) {
println("Index: \(index)")
println("Value: \(contact)")
}

First of all, you should not using init() in struct, because The
structure has initializer default.Then in this block of code:
/*
var count: Int = 0
for count in contacts {
println("\(contacts[count].name)") // here's where I get an error
}
*/
your variable "count" is not integer, it`s type is "Person".
Try this:
/*
for count in contacts {
println(count.name) // It`s must be OKey.
}
*/
I hope I help you, and sorry for my bad English:D

Related

How do you pass data dynamically is a Swift array?

Im creating a tinder like swipe app and I need a new CardData(name: "", age: "") to be created depending on how many profiles I pass through from my database. The number of cards will change. I need the number of cards created to match the the value of the results default. I have looked for the solution for a while and can't find it anywhere.
import UIKit
var nameArrayDefault = UserDefaults.standard.string(forKey: "nameArray")!
var ageArrayDefault = UserDefaults.standard.string(forKey: "ageArray")!
var nameArray = nameArrayDefault.components(separatedBy: ",")
var ageArray = ageArrayDefault.components(separatedBy: ",")
var results = UserDefaults.standard.string(forKey: "results")!
struct CardData: Identifiable {
let id = UUID()
let name: String
let age: String
static var data: [CardData] {[
CardData(name: “\(nameArray[0])”, age: “\(ageArray[0])”),
CardData(name: “\(nameArray[1])”, age: “\(ageArray[1])"),
CardData(name: “\(nameArray[2])”, age: “\(ageArray[2])”)
]}
}
You should initiate the array of CardData objects only the first time and update it after that. You can do the following
var _data = [CardData]()
var data: [CardData] {
if _data.isEmpty() {
self.initiateData()
}
return _data
}
// Initiate data for the first time only
func initiateData() -> [CardData] {
// Check that nameArray has the same size as ageArray
// If the size is different then the data are not valid.
guard nameArray.count == ageArray.count else {
return []
}
// For each of names inside nameArray create the corresponding CardData object
self.nameArray.forEach({ (index, item)
self._data.append(CardData(name: item, age: ageArray[index]))
})
}

How to add value from object in dictionary in Swift?

I have dictionary which is having objects as value, I want to retrieve value from object.
code :
public class Student {
public let name: String
public let age: Double
public init(name: String, age: Double) {
self.name = name
self.age = age
}
}
and dictionary as ["1": Student, "2" : Student ]
How can i add all the ages of student? for 13 + 12.
Here are potential solutions:
let dict = ["1": Student(name: "A", age: 13), "2" : Student(name: "B", age: 12)]
Side note, there is nothing wrong in doing a manual for loop. It's basic algorithm skills, and it's need to understand higher level methods.
Basic for loop:
var sumOfAges: Double = 0
for (_, value) in dict {
sumOfAges += value.age
}
print(sumOfAges)
Basic forEach loop
var sumOfAges2: Double = 0
dict.forEach {
sumOfAges2 += $0.value.age
}
With reduce(into:_:):
let sumOfAges3: Double = dict.reduce(into: 0) { partialResult, aKeyValue in
partialResult += aKeyValue.value.age
}
With reduce(into:_:), and using Shorthand Argument Names (which make sense only if you understand the previous step):
let sumOfAges4 = dict.reduce(into: 0, { $0 += $1.value.age })
Side note, since the output is just a number, reduce(_:_:) is enough:
let sumOfAges5 = dict.reduce(0) { $0 + $1.value.age })
Additional possible step, is to transform your dictionary into a simpler data, like an array of Double.
let allAges = dict.mapValues { $0.age }
// or let allAges = dict.mapValues { \.age }
// or let allAges = dict.values.map { $0.age }
// or let allAges = dict.values.map { \.age }
// ...
You have an array of Double, then, use either a for loop, forEach, reduce(into:_) again on this "simplified array"
The downside, is that you iterate twice, one for the mapping, one for your calculation.
Edit: Added commented alternative solutions by #Leo Dabus

Cannot assign to a property of an instance that get returned from a get-only subscript

I return an instance from a get-only subscript, but I cannot assign to a property of the returned instance
struct Student {
var id: String
var attendance = 0
var absence = 0
}
class StudentStore {
var students = [Student]()
subscript(id: String) -> Student? {
students.first(where: { $0.id == id } )
}
}
var studentStore = StudentStore()
var newStudent = Student(id: "2014901001")
studentStore.students.append(newStudent)
studentStore["2014901001"]?.attendance = 1 // error: Cannot assign to property: subscript is get-only
The subscription doesn't have a setter. What you have is the implicit getter which is a short form of
subscript(id: String) -> Student? {
get {
students.first(where: { $0.id == id } )
}
}
But it's impossible to update a value type item in an array with key subscription anyway.
An alternative is to add an update function to the store which takes the id, a keyPath and a value
func updateStudent<Value>(withID id: String, keyPath: WritableKeyPath<Student,Value>, value: Value) {
guard let index = students.firstIndex(where: {$0.id == id}) else { return }
students[index][keyPath: keyPath] = value
}
Getting the index is mandatory to be able to modify the item in the array directly.
Then you can replace
studentStore["2014901001"]?.attendance = 1
with
studentStore.updateStudent(withID: "2014901001", keyPath: \.attendance, value:1)
When you do
studentStore["2014901001"]?.attendance = 1
You are trying to set one of the Student objects in the students array, aren't you?
However, the subscript getter doesn't return (a reference to) one of the objects in the students array. Due to the value semantics of the Student struct, you return a copy of the Student object that is in the students array. You can't achieve what you want if you just set the attendance of that copy. Therefore, the Swift compiler compiles your code to something like this:
let copy = studentStore["2014901001"]
copy?.attendance = 1
studentStore["2014901001"] = copy
You can see that it sets the setter with the modified copy again. But your subscript does not have a setter, which is where the error comes from.
To solve this, you can make Student a class, which has reference semantics. This enables you to return the Student object that is in the students array, allowing the caller of the subscript to set their attendance.
class Student {
var id: String
var attendance = 0
var absence = 0
init(id: String, attendance: Int = 0, absence: Int = 0) {
self.id = id
self.attendance = attendance
self.absence = absence
}
}
Alternatively, you can add a setter. However, that would allow nonsense like this:
studentStore["1"] = Student(id: "2")
You need to decide what you want to happen here.
Error show exactly what you have to change. Because subcript will return something likes:
let updateStudent = studentStore["studentStore"]
You can not change with let
So update with this:
if var updateStudent = studentStore["studentStore"] {
updateStudent.attendance = 1
}

Inner filtering of array doesn't filter swift

I am trying to filter an array of structs that has array. Below are the data structures I am using. I want the inner array filtered also but it doesn't work
var objects = [SomeObject]() //array of objects
var filteredObject = [SomeObject]() //filtered array
var isSearching = false
struct SomeObject {
var sectionName: String
var sectionObjects : [History]
}
struct History {
var firstName: String
var lastName: Int
}
func searchBar(_ text: String) {
filteredObject = objects.filter({ (obj: SomeObject) -> Bool in
return obj.sectionObjects.filter { $0.firstName.contains(text.lowercased())}.isEmpty
})
print("====", filteredObject, "fill===")
}
let history = History(firstName: "John", lastName: 1)
let anotherHistroy = History(firstName: "Dee", lastName: 2)
let historyArray = [history, anotherHistroy]
let newObject = SomeObject(sectionName: "Section 1", sectionObjects: historyArray)
objects.append(newObject)
searchBar("Jo") // printing of filtered object should not have another history in it's sectionObjects
You might be looking for something like this:
func searchBar(_ text: String) {
filteredObject = []
for var ob in objects {
ob.sectionObjects = ob.sectionObjects.filter {
$0.firstName.contains(text)
}
if !ob.sectionObjects.isEmpty {
filteredObject.append(ob)
}
}
print("====", filteredObject, "fill===")
}
Could perhaps be done more elegantly with reduce(into:), but on the whole it is best to start simply by saying exactly what you mean. You can tweak as desired to take account of case sensitivity.

How to wrap relationship children into array in Vapor?

I have a parent-child relationship, and the children need to wrap into array how can I do it?
event.testPrices = release.testPrices
final class Event: Content {
var id: String
var inProgress: Bool?
var name: String
var purpose: String?
var testPrices: [TestPrice]
init(id: String, name: String) {
self.id = id
self.name = name
}
}
extension Release {
var testPrices: Children<Release, TestPrice> {
return children(\.releaseId)
}
}
The assignment gives the error:
Cannot assign value of type 'Children' to type '[TestPrice]'
You can use a query to form the Future array and then map it. Assuming you are in some controller/route where event contains the appropriate Event and release contains the appropriate Release, try this:
{
release, event in
_ = release.testPrices.query(on:request).all().map { testP in
// testP is now [TestPrice]
event.testPrices = testP
}
}