problems with forEach loop - swift

struct Response: Codable {
let status: String
let value: [Value]
}
struct Value: Codable {
let psid: Int
let name: String
let valute: String
let reserve: Double
let with_codes: Int
let img: String
}
var good = [Value]()//first array
struct Response1: Codable {
let status: String
let value: [Value1]
}
struct Value1: Codable {
let id: String
let enabled: Int
let direct: Int
let psid1: Int
let psid2: Int
let in: Int
let in_valute: String
let out: Double
let out_valute: String
let in_min: Double
let in_max: Int
let reserve: Double
}
var good1 = [Value1]()//second array
good.forEach { goodItem in
if good1.contains(where: { good1Item -> Bool in
return good1Item.psid2 == goodItem.psid
}) {
print(goodItem)
}
}
The problem is that when I need to output goodItem.name to a table, only the last value is output, although when I check everything in the console, google I found that the return method returns only the last value, how can I fix it?

This worked for me:
for value in good {
if good1.filter( {$0.psid2 == value.psid}).count > 0 {
print(value.name)
}
}

Related

I want to write a function that returns text and an integer inside an if statement in Swift

I want to create a function that returns both text and integer. And I want to have an if loop inside this function. If the number of steps of the 1st user is more than the 2nd, the step difference of these two users and a text that says you are ahead should be returned.If the 2nd user has more steps than the 1st user, I want it to return a text saying that there is a difference in the number of steps between them and you are behind.
In my hand like this.
struct ActiveDuel{
let state: String
let user1StepCount: Int
let user2StepCount: Int
let user1Name: String
let user2Name: String
let user1Phote: String
let user2Phote: String
let stepDif: Int
let goldAmount: Int
let time: Int
let lastUpdateTime: Int
let startTime: Int
let docId: String
}
I created the code like this but it looks wrong and also doesn't contain text.
func DıfferenceStep(user1StepCount:Int , user2StepCount: Int ) -> Int{
if user1StepCount > user2StepCount {
let DıfferenceStepFunc = user1StepCount - user2StepCount
}else if user2StepCount > user1StepCount {
let DıfferenceFalseStep = user2StepCount - user1StepCount
}
}
I don't know how to use if statement inside functions and besides that I want it to return both integer and text.I would be glad if you help me in this regard.
Here is an example of your struct with a func inside it. You create the struct and then call the func on the struct instance.
struct ActiveDuel
{
var user1StepCount: Int = 0
var user2StepCount: Int = 0
var user1Name: String?
var user2Name: String?
func stepsDifference() -> Int
{
return abs(user1StepCount - user2StepCount)
}
}
let duel = ActiveDuel(user1StepCount: 30, user2StepCount: 5, user1Name: "Bill", user2Name: "Ted")
print(duel.stepsDifference())
I would consider making a Duelist struct and store each duelist's individual information in that instead of in the general ActiveDuel struct. Then you could have a Duel struct that had an active Bool property (true/false), and any number of Duelists (you could limit it to two).
Depending on how you use this it would be better to create 2 different computed properties in your ActiveDuell struct. One returning the difference in points and one returning a string that gives the information you want.
struct ActiveDuel{
let state: String
let user1StepCount: Int
let user2StepCount: Int
let user1Name: String
let user2Name: String
let user1Phote: String
let user2Phote: String
let stepDif: Int
let goldAmount: Int
let time: Int
let lastUpdateTime: Int
let startTime: Int
let docId: String
var pointDifference: Int{
// calculate the difference and make the result positive
abs(user1StepCount - user2StepCount)
}
var standings: String{
// if the difference is 0 the game is tied
if user1StepCount == user2StepCount{
return "you are tied"
} else {
// put the name of the leader and the points they lead in to the string
return "\(user1StepCount > user2StepCount ? user1Name : user2Name), you lead by \(pointDifference) points"
}
}
}
you can use it like this:
let activeDuel = ActiveDuel(user1StepCount: 12, user2StepCount: 10, user1Name: "Player1",.....
print(activeDuel.standings) // prints "Player1, you lead by 2 points

passing a struct type as a parameter throwing initialization error

I have the following code which has 3 objects which are then part of a 4th object. I'm getting errors trying to create the init method for the aggregate object (GTFS) because I'm passing (or trying to pass) the type of the 3 component objects (Stop, Route, Trip). I'm not sure why those have to be initialized before just their types being used.
protocol GTFSObject {
static var fileName: String { get }
init(csvRow: [String: String])
}
struct Stop: GTFSObject {
static let fileName = "stops.txt"
let stopID: String
let stopCode: String
let stopName: String
let stopDesc: String
let stopLat: Double
let stopLon: Double
let locationType: Int
let parentStation: String
init(csvRow: [String: String]) {
self.stopID = csvRow["stop_id"]!
self.stopCode = csvRow["stop_code"]!
self.stopName = csvRow["stop_name"]!
self.stopDesc = csvRow["stop_desc"]!
self.stopLat = Double(csvRow["stop_lat"]!)!
self.stopLon = Double(csvRow["stop_lon"]!)!
self.locationType = Int(csvRow["location_type"]!)!
self.parentStation = csvRow["parent_station"]!
}
}
struct Trip: GTFSObject {
static let fileName = "trips.txt"
let routeID: String
let serviceID: String
let tripID: String
init(csvRow: [String: String]) {
tripID = csvRow["trip_id"] ?? ""
routeID = csvRow["route_id"] ?? ""
serviceID = csvRow["service_id"] ?? ""
}
}
struct Route: GTFSObject {
static let fileName = "trips.txt"
let routeID: String
let agencyID: String
let routeShortName: String
let routeLongName: String
let routeDesc: String
let routeType: Int
let routeURL: String
let routeColor: String
let routeTextColor: String
init(csvRow: [String: String]) {
routeID = csvRow["route_id"] ?? ""
agencyID = csvRow["agency_id"] ?? ""
routeShortName = csvRow["route_short_name"] ?? ""
routeLongName = csvRow["route_long_name"] ?? ""
routeDesc = csvRow["route_desc"] ?? ""
routeType = Int(csvRow["route_type"] ?? "0") ?? 0
routeURL = csvRow["route_url"] ?? ""
routeColor = csvRow["route_color"] ?? ""
routeTextColor = csvRow["route_text_color"] ?? ""
}
}
class GTFS {
let routes: [Route]
let stops: [Stop]
let trips: [Trip]
init(gtfsFolderUrl: URL) {
self.stops = init_struct_from_url(gtfsFolderUrl: gtfsFolderUrl, type: Stop.self)
self.trips = init_struct_from_url(gtfsFolderUrl: gtfsFolderUrl, type: Trip.self)
self.routes = init_struct_from_url(gtfsFolderUrl: gtfsFolderUrl, type: Route.self)
}
private func init_struct_from_url<GTFSType>(gtfsFolderUrl: URL, type: GTFSType.Type) -> [GTFSType] where GTFSType : GTFSObject{
var returnList: [GTFSType] = []
let rows = try! NamedCSV(url: GTFS_FOLDER_URL.appendingPathComponent(type.fileName), delimiter: CSVDelimiter.comma, loadColumns: false).rows
for row in rows {
returnList.append(type.init(csvRow: row))
}
return returnList
}
}
The error I get is
'self' used in method call 'init_struct_from_url' before all stored properties are initialized
I don't know why I have to initialize the properties of the struct just to pass the type of the struct to this other function. What am I missing?
It's not about the three types that you are passing to init_struct_from_url. It's about the call init_struct_from_url itself.
You are actually calling:
self.init_struct_from_url(...)
^^^^^
The error is saying that that use of self is not allowed, because self is not initialised. If init_struct_from_url uses a property in self, it could see an uninitialised value.
Since init_struct_from_url doesn't actually use self at all and is just a helper function, you can make it an inner function of init:
init(gtfsFolderUrl: URL) {
func structFromUrl<GTFSType>(gtfsFolderUrl: URL, type: GTFSType.Type) -> [GTFSType] where GTFSType : GTFSObject{
var returnList: [GTFSType] = []
let rows = try! NamedCSV(url: GTFS_FOLDER_URL.appendingPathComponent(type.fileName), delimiter: CSVDelimiter.comma, loadColumns: false).rows
for row in rows {
returnList.append(type.init(csvRow: row))
}
return returnList
}
self.stops = structFromUrl(gtfsFolderUrl: gtfsFolderUrl, type: Stop.self)
self.trips = structFromUrl(gtfsFolderUrl: gtfsFolderUrl, type: Trip.self)
self.routes = structFromUrl(gtfsFolderUrl: gtfsFolderUrl, type: Route.self)
}

Nil data returned when copying "working" json data to new struc array

Weird. I swear this was working but then it just stopped working .. or ... Please ignore the i+i ,I will clean this up...
I don't have a clue why but myrecords?[i].title is returning nil. The json.releases[i].date_adde is working fine and full of data. I can "print" it and get a result. but when I go to copy it to the myrecords it is returning nil.
I download the data from JSON, that works fine. then I try to copy the data to a struc array I can get to in other parts of my app and now my myrecords data is empty. what the heck am I doing wrong?
import Foundation
var numberOfRecords : Int = 0
struct routine {
var dateadded : String
var title : String
var artist : String
var year : Int
var recordlabel : String
}
var myrecords: [routine]?
//-------------------------------------------------------------
struct Response: Codable {
var pagination: MyResult
var releases: [MyReleases]
}
public struct MyResult: Codable {
var page: Int
var per_page: Int
var items: Int
}
public struct MyReleases: Codable {
var date_added: String
var basic_information: BasicInformation
}
public struct BasicInformation: Codable {
var title: String
var year: Int
var artists : [Artist]
var labels: [Label]
}
public struct Artist: Codable {
var name: String
}
public struct Label: Codable {
var name: String
}
let url = "https://api.discogs.com/users/douglasbrown/collection/folders/0/releases?callback=&sort=added&sort_order=desc&per_page=1000"
public func getData(from url: String) {
let task = URLSession.shared.dataTask(with: URL(string: url)!, completionHandler: { data, response, error in
guard let data = data, error == nil else {
print("something went wrong")
return
}
//HAVE DATA
var result: Response?
do {
result = try JSONDecoder().decode(Response.self, from: data)
}
catch {
print("Converion Error:\(error.localizedDescription)")
}
guard let json = result else {
return
}
numberOfRecords = json.pagination.items
var i: Int
i = -1
for _ in json.releases {
i = i + 1
myrecords?[i].dateadded = json.releases[i].date_added
myrecords?[i].title = json.releases[i].basic_information.title
myrecords?[i].artist = json.releases[i].basic_information.artists[0].name
myrecords?[i].year = json.releases[i].basic_information.year
myrecords?[i].recordlabel = json.releases[i].basic_information.labels[0].name
print(">>>>>>\(myrecords?[i].dateadded)")
}
})
task.resume()
}
You haven't initialized myrecords array.
Otherwise, you cannot use subscript like myrecords[i] when you don't know the capacity of array, it can be out of index.
First, initialize your array.
var myrecords: [routine]? = []
Second, append new element to array instead of using subscript
for _ in json.releases {
let newRecord = routine()
newRecord.dateadded = json.releases[i].date_added
newRecord.title = json.releases[i].basic_information.title
newRecord.artist = json.releases[i].basic_information.artists[0].name
newRecord.year = json.releases[i].basic_information.year
newRecord.recordlabel = json.releases[i].basic_information.labels[0].name
myrecords.append(newRecord)
}
This is the answer. :) THANK YOU All for pointing me in the right direction
struct Routine {
var dateadded : String
var title : String
var artist : String
var year : Int
var recordlabel : String
}
var myRecords: [Routine] = []
var i : Int
i = -1
for _ in json.releases {
var newRecord = Routine.self(dateadded: "", title: "", artist: "", year: 0, recordlabel: "")
i = i + 1
newRecord.dateadded = json.releases[i].date_added
newRecord.title = json.releases[i].basic_information.title
newRecord.artist = json.releases[i].basic_information.artists[0].name
newRecord.year = json.releases[i].basic_information.year
newRecord.recordlabel = json.releases[i].basic_information.labels[0].name
myRecords.append(newRecord)
}
print(">>>>\(myRecords[0].dateadded)")
I will clean up the bad code too but it works and that is good! :)

Accept Float, Double or Int in Swift `init` to convert to String

I'm attempting to convert a value to a string in an init. That value can be an Int, Double, or Float.
For example:
struct example {
var string: String
init(number: Int) {
string = String(number)
}
}
I would like to say something like below (I'm using Typescript as an example - this obviously doesn't work, but I want number to be any of those three types - all of which String can convert).
struct example {
var string: String
init(number: Int | Float | Double) {
string = String(number)
}
}
Edit: I realized I have another issue. I need to convert back from a string to the type of Int or Double or Float. Using one of the answers below, I'm trying to figure out how to implement getNumberWith5:
struct example2<N: Numeric & CustomStringConvertible>: CustomStringConvertible {
#Binding var number: N
init(number: Binding<N>) {
self._number = number
}
var description: String {
String(describing: number)
}
mutating func getNumberWith5() {
// How do I update number to the type N?
self.number = howDoIConvertToN(description + "5")
}
}
Or from another answer:
struct example3<N: Numeric> {
#Binding var number: N
var string: String
init(number: Binding<N>) {
self._number = number
self.string = "\(number)"
}
mutating func getNumberWith5() {
// How do I update number to the type N?
self.number = howDoIConvertToN(string + "5")
}
}
Edit2 My Answer:
I attempted to create an equivalent of type unions (as Typescript has) using enums in Swift based on this article. But it was challenging to then assign back to that value. I've decided Swift just doesn't have first class support for type unions like Typescript has. So, I used the accepted answer below and this seems to work.
extension String {
func numeric<N: Numeric & LosslessStringConvertible>() -> N? {
N(self)
}
}
struct example4<N: Numeric & LosslessStringConvertible> {
#State var string: String
#Binding var number: N
init(number: Binding<N>) {
self._number = number
self.string = String(describing: number)
}
mutating func getNumberWith5() {
let newString = string + "5"
number = newString.numeric() ?? 0
}
}
Actually if all you want is a string representation of Int Float Double or any other standard numeric type you only need to know that they conform to CustomStringConvertible and use String(describing:).
Or you can use conformance to Numeric and CustomStringConvertible:
struct example {
var string: String
init<C: CustomStringConvertible & Numeric>(number: C) {
string = String(describing: number)
}
}
and maybe even better example itself could conform to CustomStringConvertible
struct example: CustomStringConvertible {
var description: String
init<C: CustomStringConvertible & Numeric>(number: C) {
description = String(describing: number)
}
}
yet another way :
struct example<N: Numeric & CustomStringConvertible>: CustomStringConvertible {
let number: N
init(number: N) {
self.number = number
}
var description: String {
String(describing: number)
}
}
EDIT
I think what you want is a custom Property Wrapper not #Binding:
#propertyWrapper struct CustomStringConversion<Wrapped: CustomStringConvertible> {
var wrappedValue: Wrapped
init(wrappedValue: Wrapped) {
self.wrappedValue = wrappedValue
}
var projectedValue: String { .init(describing: wrappedValue) }
}
struct Foo {
#CustomStringConversion var number = 5
}
let foo = Foo()
let number: Int = foo.number // 5
let stringRepresentation: String = foo.$number // "5"
But as #LeoDabus pointed out using LosslessStringConvertible may be better :
struct example<N: Numeric & LosslessStringConvertible>: LosslessStringConvertible {
let number: N
init(number: N) {
self.number = number
}
init?(_ description: String) {
guard let number = N(description) else { return nil }
self.number = number
}
var description: String {
.init(number)
}
}
let bar = example(number: Double.greatestFiniteMagnitude) // 1.7976931348623157e+308
let baz: example<Double>? = example("1.7976931348623157e+308") // 1.7976931348623157e+308
Use generic structure with Numeric protocol.
struct Example<T:Numeric> {
var string: String
init(number: T) {
self.string = "\(number)"
}
}
struct Example {
var string: String
init(number: Int) {
string = String(number)
}
init(number: Float) {
string = String(number)
}
init(number: Double) {
string = String(number)
}
}
You can have a look at how swift does this with its String-initializer:
struct Example {
init<Number>(number: Number) where Number: BinaryInteger {
string = String(number)
}
}

decoding an array of objects in swift

I have an array of objects
{"total_rows":5,"offset":0,"rows":[
{"id":"index","key":"index","value":{"rev":"4-8655b9538706fc55e1c52c913908f338"}},
{"id":"newpage","key":"newpage","value":{"rev":"1-7a27fd343ff98672236996b3fe3abe4f"}},
{"id":"privacy","key":"privacy","value":{"rev":"2-534b0021f8ba81d09ad01fc32938ce15"}},
{"id":"secondpage","key":"secondpage","value":{"rev":"2-65847da61d220f8fc128a1a2f1e21e89"}},
{"id":"third page","key":"third page","value":{"rev":"1-d3be434b0d3157d7023fca072e596fd3"}}
]}
that I need too fit in struct and then decode in swift. My current code is:
struct Index: Content {
var total_rows: Int
var offset: Int
// var rows: [String: String] // I don't really know what I am doing here
}
and the router (using vapor)
router.get("/all") { req -> Future<View> in
let docId = "_all_docs"
print(docId)
let couchResponse = couchDBClient.get(dbName: "pages", uri: docId, worker: req)
guard couchResponse != nil else {
throw Abort(.notFound)
}
print("one")
return couchResponse!.flatMap { (response) -> EventLoopFuture<View> in
guard let data = response.body.data else { throw Abort(.notFound) }
print(data)
let decoder = JSONDecoder()
let doc = try decoder.decode(Index.self, from: data)
let allDocs = Index(
total_rows: doc.total_rows,
offset: doc.offset
//rows: doc.rows
)
print("test after allDocs")
return try req.view().render("index", allDocs)
}
}
to summarise all is fine for the first level (total rows and offset are int and properly decoded) but how can I include in my structure the rows: array and assign thee parsed values to it ?
You're on the right road, you just need to keep going.
struct Index: Decodable {
var total_rows: Int
var offset: Int
var rows: [Row]
}
Then you define a Row:
struct Row: Decodable {
var id: String
var key: String
var value: Value
}
It's not really clear what a Value is in this context, but just to keep the structure.
struct Value: Decodable {
var rev: String
}
And that's all.
let index = try JSONDecoder().decode(Index.self, from: jsonData)