Extract a String to array of CGPoints in Swift - arrays

I have a string containing a list of thousands of geo coordinates
"[8.2627925,46.3460497],[8.2612673,46.3457009],[8.2602494,46.3453934],..."
and would like to extract all of them in an array of CGPoints.
The code I am using today is the following:
let coords=[CGPoint]()
while substring.contains("[")
{
index = substring.index(of: "[")!
substring = substring[index...]
index = substring.index(of: "]")!
let coordinate = substring[..<index]
var indexComma = coordinate.index(of: ",")!
let coordX = String(coordinate[..<indexComma])
indexComma = coordinate.index(indexComma, offsetBy: +1)
let coordY = String(coordinate[indexComma...])
coords.append(CGPoint(x: CGFloat(Double(coordX)!), y: CGFloat(Double(coordY)!)))
substring = substring[index...]
}
However I am sure it can be optimised, possibly using regex. What would be the most efficient way ?

One of the better efficient way is using to json serialization. Json can not serialize your string because its not in to correct format so you can insert "[" and "]" for serialize it like below
var coordinates = "[1.3123,3.2131],[2.3123,4.213]"
coordinates.insert("[", at: coordinates.startIndex)
coordinates.insert("]", at: coordinates.endIndex)
Now , our data is ready for serialization.Then the easiest part is appending poinst to CGPoint array
var points : [CGPoint] = []
if let data = coordinates.data(using: .utf8),
let jsonArray = try? JSONSerialization.jsonObject(with: data) as? [[Double]] {
points.append(contentsOf: jsonArray.map{CGPoint(x: $0[0], y: $0[1]) })
print(points)
}
You can easily reach ur datas
print(points[0].x) // 1.3123
print(points[1].y) // 4.213

Related

Add values from multiple dictionaries in firebase into an Int

I'm using firebase to store the amount of views every video in my app has been seen. What I want to is to gather all views from from one users all videos and display the total number of views. However I'm having problems fetching down the data and putting all the dictionary values together into a Int/String!
Ive tried many different solutions so far, but still I get all the different values in like array / values of the dictionary instead of everything added into one value
This is my code for getting all the videoviews of a specific user, no problems with this so far. When I print "intConvert" I get like all the views in different rows.
let ref = Database.database().reference().child("videoviews").child(stringUid)
ref.observe(.value, with: { (snapshot) in
if let dictionary = snapshot.value as? [String: AnyObject]{
let numbOfViews = dictionary["views"] as! String
let intConvert = Int(numbOfViews)!
let ArrayViews = [intConvert]
This is my database structure:
**videoviews**
-Lb52VxrEqdSRGljJdP7
views: "25"
-Lb53ARq_lOHEbTruW8s
views: "273"
-Lb53A_cEyX3CYc4mKYn
views: "38"
EDIT: If I do print(dictionary), the dictionary from "if let dictionary = snapshot.value as? [String: Anyobject] looks like this:
["views": 642]
["views": 660]
["views": 628]
["views": 630]
["views": 615]
["views": 3]
["views": 0]
["views": 2]
["views": 1]
Edit: (I was confused and forgot to add the bracelets, sorry for that.)
when I do I "print(dictionary.values) the console looks like this (the key values from different dictionaries):
[642]
[660]
[628]
[630]
[615]
[3]
[0]
[2]
[1]
I then tried to put this together in a loop like this:
var bLoader = 0.0
for hejArray in 0...ArreyViews.count-1{
bLoader += Double(Arrej[hejArray])
}
But when I print "bLoader" I still get all the views for every video in different rows instead of gathered in one value.
So what do I need to do put together all the values from different dictionaries in Firebase into one Variable?
I appreciate all help I can get with this, I can imagine it shouldn't be too hard but that im missing out on something.
EDIT /// I finally found the problem. the "StringUid" that I passed in have different amount of values and therefore the whole function would be called for 9 times if the videos of the user had the amount of 9. The solution that finally worked looked like this:
Global Array declaration:
var myArray = [String]()
Inside the function:
if let dictionary = snapshot.value as? [String: AnyObject]{
let numbOfViews = dictionary["views"] as! String
let intConvert = Int(numbOfViews)!
self.myArray.append(numbOfViews)
let intArray = self.myArray.map { Int($0)!}
let total = intArray.reduce(0, +)
self.totalViewsShower2.text = String(total)
Thank you in advance!
Update
If you can directly print the values from your dictionary like that then the solution might be as easy as
let total = dictionary.values.reduce(0, +)
or if values are strings you need to convert them to Int
let total = dictionary.values.reduce(0) {sum, value -> Int in return sum + (Int(value) ?? 0)}
If on the other hand they values are string but defined as Any you need an extra cast
let total2 = dictionary2.values.reduce(0) {sum, value -> Int in
if let str = value as? String {
return sum + (Int(str) ?? 0)
}
return 0
}
I am not exactly sure what your dictionary contains but I assumed something like this
let dictionary: [String: Any] = ["views": ["1", "2", "3"]]
Then you can cast the value for the "views" key to a String array and then use reduce on that array to get the sum
let array = dictionary["views"] as! [String]
let total = array.reduce(0) {sum, value -> Int in return sum + (Int(value) ?? 0)}
According to your Database structure which looks something like this
{
"videoviews": {
"Lb52VxrEqdSRGljJdP7": {
"views": "25"
},
"Lb53ARq_lOHEbTruW8s": {
"views": "273"
},
"Lb53A_cEyX3CYc4mKYn": {
"views": "38"
}
}
}
let ref = Database.database().reference().child("videoviews").child(stringUid)
ref.observe(.value, with: { (snapshot) in
if let dictionary = snapshot.value as? [String: AnyObject] {
let viewsArray = dictionary.values
.compactMap { $0 as? [String: String] }
.compactMap { Int($0["views"] ?? "") }
let totalViews = viewsArray.reduce(0, +)
}
})

Fetch Core Data as comma separated list

I realise that I am missing something simple but as a Swift newbie I am going around in circles & would appreciate a pointer as to what I am doing wrong?!
I have a Core Data Entity called "Numbers" with an attribute (Int16) called "userNumbers". I am fetching the results like:
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let context = appDelegate.persistentContainer.viewContext
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Numbers")
//request.predicate = NSPredicate(format: "age = %#", "12")
request.returnsObjectsAsFaults = false
do {
let result = try context.fetch(request)
for data in result as! [NSManagedObject] {
print("\(data.value(forKey: "userNumbers") as! Int16)")
}
} catch {
print("Failed")
}
The result in my console is:
12
13
18
19
21
I need to know how to make this a comma separated list so I can use it in an array. Essentially I need the return to be: 12,13,18,19,21
Everything I try seems to be wrong!
First of all create a more specific fetch request to get a distinct result type
let request = NSFetchRequest<Numbers>(entityName: "Numbers")
A comma separated list is not possible because the type of userNumbers is numeric.
You can map the result to an array of Int16 with
do {
let result = try context.fetch(request) // the type is [Numbers]
let numberArray = result.map{$0.userNumbers}
print(numberArray)
}

Convert type from string to string array

I want to remove schedule notifications from my app for this I need String array to remove pending notifications I have this type of string its not array this return String from fbdb database but I want array
["01D94B0E-F1AB-421E-9EC3-4A78F0211ED8",
"76E16E51-CB59-4D3F-939E-4D492FFB22BE",
"97696EBD-252F-4A12-962E-995EF306B557",
"84EB98BB-14EB-4D19-83F6-798DCF75E3CD",
"B55621AE-B124-4767-8D6E-C728598E5279"]
I have this is in Array format how can I do this? I know this is beginner question hope u guys will help
let str = """["01D94B0E-F1AB-421E-9EC3-4A78F0211ED8", "76E16E51-CB59-4D3F-939E-4D492FFB22BE", "97696EBD-252F-4A12-962E-995EF306B557", "84EB98BB-14EB-4D19-83F6-798DCF75E3CD", "B55621AE-B124-4767-8D6E-C728598E5279"]"""
let ids = try? JSONSerialization.jsonObject(with: Data(str.utf8)) as? [String] ?? []
you can use default JSONDecoder...
import Foundation
var stringToData: Data? = "[\"01D94B0E-F1AB-421E-9EC3-4A78F0211ED8\", \"76E16E51-CB59-4D3F-939E-4D492FFB22BE\", \"97696EBD-252F-4A12-962E-995EF306B557\", \"84EB98BB-14EB-4D19-83F6-798DCF75E3CD\", \"B55621AE-B124-4767-8D6E-C728598E5279\"]".data(using: .utf8)
let decoded = try JSONDecoder().decode(Array<String>.self, from: stringToData!)
print(decoded)
output:
["01D94B0E-F1AB-421E-9EC3-4A78F0211ED8", "76E16E51-CB59-4D3F-939E-4D492FFB22BE", "97696EBD-252F-4A12-962E-995EF306B557", "84EB98BB-14EB-4D19-83F6-798DCF75E3CD", "B55621AE-B124-4767-8D6E-C728598E5279"]
You can try
let str = """
["1","2","3"]
"""
let res = str.dropFirst(1).dropLast(1)
let arr = res.components(separatedBy: ",").map { $0.replacingOccurrences(of: "\"", with: "") }

"Extra argument in call" error when using zip() to iterate over multiple arrays

I'm trying to iterate over multiple arrays then place everything into one other array.
This is my class that I'm going to loop into:
class Place {
var names = [String]()
var messages = [String]()
var latidudes = [Double]()
var longitudes = [Double]()
var locations = [CLLocationCoordinate2D]()
}
And this is my function:
private func placesArrayLoop() {
let CoffeeShopNames = ["aCoffee","bCoffee", "cCoffee"]
let messages = ["message0", "message1", "message2"]
let latitudes = [40.232320, 40.232321, 40.232322]
let longitudes = [-95.388069, -95.388068, 95.388067]
for (name, message, latitude, longitude) in zip(CoffeeShopNames, messages, latitudes, longitudes) {
let place = Place()
place.names.append(name)
place.messages.append(message)
place.latitudes.append(latitude)
place.longitudes.append(longitude)
}
}
It is giving me the error, "extra argument in call pointing to latitudes in the zip array line. I'm assuming it's a syntax error new to swift 3, but I've looked around and cant find how to fix it. But the code bellow works...
let strArr1 = ["Some1", "Some2", "Some3"]
let strArr2 = ["Somethingelse1", "Somethingelse2", "Somethingelse3"]
for (e1, e2) in zip(strArr1, strArr2) {
print("\(e1) - \(e2)")
}
So now I'm really confused.
The zip() function only takes two arguments (hence why your second example works).
http://swiftdoc.org/v3.0/func/zip/
You are trying to pass it four arguments.

How to return an subset of Array of characters?

I am trying to dynamically chop an array of letters but I can't seem to reconvert the result back into a [String]
let letters:String = "abcdefghijklmnopqrstuvwxyz"
let lettersarray = Array(letters.characters)
var targetNum = 14 // Show just the first 14 characters
var resultsArray = [String]()
let resultsSlice = lettersarray.dropLast(lettersarray.count - targetNum) // Returns an Array Slice instead of an Array
let newresultsArray = Array(resultsSlice) // Returns Array<_element> instead of [String]
How do I return a [String] ie ["a","b","c"... eg]
You need to map the Character array back to String
let resultsArray = lettersarray.dropLast(lettersarray.count - targetNum).map{String($0)}
alternatively (credits to Leo Dabus)
let letters = "abcdefghijklmnopqrstuvwxyz"
let targetNum = 14
let resultsArray = letters.characters.prefix(targetNum).map{String($0)}
No need for an array here. It's hard to understand what you're trying to do, but if you just want the first 14 characters of a string, use the prefix method:
let s = String("abcdefghijklmno".characters.prefix(14))
Assuming that you are getting a String and want an array of characters which is a slice of characters from that String, you could use Swift's Half-Open Range Operator found here.
let letters:String = "abcdefghijklmnopqrstuvwxyz"
let lettersArray = Array(letters.characters)
let targetNum = 2
let resultsArray = lettersArray[0..<targetNum]
This will give you an ArraySlice<Character>. If you want an Array<Character> you could do this:
let resultsArray:Array<Character> = Array(lettersArray[0..<targetNum]) // ["a","b"]

Resources