I have a problem, I get a Json. The data comes in a dictionary.
This is a sample json:
Receivedtext: {
"x": "pricef",
"b": "usd",
"ds": [
"tpr",
"avgp",
"mcap",
"ppc7D",
"ppc12h",
"ppc4h",
"ppc24h"
],
"data": [
[
"ADA/USD",
"0.819",
"21.23B",
"6.09",
"-5.45",
"-5.36",
"-10"
],
[
"AVT/USD",
"5.968",
"35.81M",
"24.33",
"-4.51",
"-3.3",
"6.65"
],
[
"BAT/USD",
"0.946",
"unknown",
null,
null,
null,
null
], [
"FUN/USD",
"0.000",
"0.00",
0,
0,
0,
0
] ]
}
Normally the json should be all String. I can handle the nill/null but I dont know how to handle if its Int/Double.
If it is a Int/Double I want to replace the value with "unknown".
This is my code so far:
struct JsonMaintableWebsocket {
let tpr: String?
let avgp: String?
let mcap: String?
let ppc7D: String?
let ppc12h: String?
let ppc4h: String?
let ppc24h: String?
init(json: [String?]) {
self.tpr = json[0]
self.avgp = json[1]
self.mcap = json[2]
self.ppc7D = json[3]
self.ppc12h = json[4]
self.ppc4h = json[5]
self.ppc24h = json[6]
}
static func fetchJsonWebsocketMaintable(json: Data) -> [JsonMaintableWebsocket] {
var jsonWebsocket: [JsonMaintableWebsocket] = []
do {
let jsonData = try JSONSerialization.jsonObject(with: json, options: []) as? [String: Any?]
if let data = jsonData!["data"] as? [[String?]] {
for d in data {
jsonWebsocket.append(JsonMaintableWebsocket(json: d))
}
}
}
catch let error{
print(error.localizedDescription)
}
return jsonWebsocket
}
}
Thanks a lot!
One way you could handle this would be to map over the array and check to see what kind of value is stored, and act accordingly. You might change this part:
if let data = jsonData!["data"] as? [[String?]] {
for d in data {
jsonWebsocket.append(JsonMaintableWebsocket(json: d))
}
}
to this:
if let data = jsonData!["data"] as? [[Any?]] {
for d in data {
let adjustedArray: [String?] = d.map({
//First, check to see if object is nil, and return nil if so
if $0 == nil {
return nil
//Check to see if value is string, and return string
} else if let stringValue = $0 as? String {
return stringValue
//Otherwise return "unknown"
} else {
return "unknown"
}
})
jsonWebsocket.append(JsonMaintableWebsocket(json: adjustedArray))
}
}
It would also be easy to handle Int or Double as Strings as well, by adding a couple more options:
if let data = jsonData!["data"] as? [[Any?]] {
for d in data {
let adjustedArray: [String?] = d.map({
if $0 == nil {
return nil
} else if let stringValue = $0 as? String {
return stringValue
} else if let intValue = $0 as? Int {
return "\(intValue)"
} else if let doubleValue = $0 as? Double {
return "\(doubleValue)"
} else {
return "unknown"
}
})
jsonWebsocket.append(JsonMaintableWebsocket(json: adjustedArray))
}
}
Related
Im reading documents from firebase and putting them into an Array. The output of my array is:
[MainApp.Message(name: Optional("Bluesona"), userId:
Optional("7epbTeafCAS51ctDxWWt0xIAWN03"), msg: Optional(""), creatAt:
Optional(1535028200082), latitude: Optional("0.00"), longitude:
Optional("0.00")), MainApp.Message(name: Optional("Oliver"), userId:
Optional("7epbTeafCAS51ctDxWWt0xIAWN03"), msg: Optional(""), creatAt:
Optional(1537440120260), latitude: Optional("54.976663"), longitude:
Optional("-7.732037")), MainApp.Message(name: Optional("Oliver"),
userId: Optional("7epbTeafCAS51ctDxWWt0xIAWN03"), msg: Optional(""),
creatAt: Optional(1537639139566), latitude: Optional("54.976726"),
longitude: Optional("-7.731986"))]
How can I then manipulate my array to only display items which have name "Bluesona"?
Here is the code where I'm creating my array
firebaseDB.collection("message").document(key).collection("messages").getDocuments() { (querySnapshot, err) in
if let err = err {
print("Error getting documents: \(err)")
}
else {
self.dataArr.removeAll()
for document in querySnapshot!.documents {
print("\(document.documentID) => \(document.data())")
let msgdata = document.data() as! [String:Any]
var msgObj = Message()
if let name = msgdata["name"] as? String {
msgObj.name = name
}
if let latitude = msgdata["latitude"] as? String {
msgObj.latitude = latitude
}
if let long = msgdata["longitude"] as? String {
msgObj.longitude = long
}
if let uid = msgdata["userId"] as? String {
msgObj.userId = uid
}
if let time = msgdata["createdAt"] as? Int {
msgObj.creatAt = time
}
self.dataArr.append(msgObj)
// self.dataArr.append(document.data() as [String:Any])
}
self.dataArr = self.dataArr.sorted(by: {$0.creatAt < $1.creatAt })
self.tblMessage.reloadData()
if self.dataArr.count < 1 {
print("No Messages")
}
else{
//self.tblMessage.scrollToRow(at: IndexPath(row: self.dataArr.count - 1, section: 0), at: .bottom, animated: true)
print(self.dataArr)
}
}
}
You can use filter to achieve your goals.
...
self.dataArr = self.dataArr.sorted(by: {$0.creatAt < $1.creatAt })
self.dataArr = dataArr.filter { $0.name == "Bluesona"}
self.tblMessage.reloadData()
...
Or you can also use removeAll(where:) introduced in Swift4.2:
...
self.dataArr = self.dataArr.sorted(by: {$0.creatAt < $1.creatAt })
self.dataArr.removeAll(where: { $0.name != "Bluesona"})
self.tblMessage.reloadData()
...
I am having the Json data as shown below in this I need to get the data that which key value pair for default is 1 then i need to get the remaining dictionaries data and need to be passed to the user to display can any one tell me how to implement this ?
And my code is as shown below
if let addressArray = jsonObj!.value(forKey: "address") as? NSArray{
for array in addressArray {
if let addressDict = array as? NSDictionary{
if let Default = addressDict.value(forKey: "default"){
}
}
}
}
"address": [
{
"default": 0,
"number": 9123456711,
"name": "Ramesh",
"address": "No:11/111 ,cross street,Nungambakkam,mylapore,chennai :600088"
},
{
"default": 1,
"number": 8123456722,
"name": "Vignesh",
"address": "No:22/222 ,cross street,Perambur,chennai :600012"
},
{
"default": 0,
"number": 7123456733,
"name": "Rajesh",
"address": "No:33/333 ,cross street,Villivakkam,chennai :600045"
}
]
You can check if Default equals 1 and add those values to an array.
var defaultArray = [NSDictionary]()
if let addressArray = jsonObj!.value(forKey: "address") as? NSArray{
for array in addressArray {
if let addressDict = array as? NSDictionary{
if let Default = addressDict.value(forKey: "default"){
if Default == 1 {
defaultArray.append(addressDict)
}
}
}
}
}
Step1: Prepare your model as shown in below code snippet.
class Addresses: NSObject {
var default = 0
var number = 0
var name = String()
var address = String()
init?(dictionary:[String:Any]) {
guard let default = dictionary["default"],
let number = dictionary["number"],
let name = dictionary["name"],
let address = dictionary["address"]
else {
return nil
}
self.default = default
self.number = number
self.name = name
self.address = address
}
}
Step2: Declare an array to store parsed addresses.
var addressesArray = [Addresses]()
Step3:
if let addressArray = jsonObj!.value(forKey: "address") as? NSArray{
for array in addressArray {
if let addressDict = array as? NSDictionary{
if let defaultValue = addressDict.value(forKey: "default") as? Int{
if defaultValue == 1 {
if let address = Addresses(dictionary: addressDict) {
addressesArray.append(address)
}
}
}
}
}
}
Thats it, take care of datatypes, and you can use addressesArray to display data.
I have the following array which is passed from an API call from a PHP Script:
["playerForm": {
1 = (
{
date = "2017-01-31";
name = Dicky;
result = L;
"results_id" = 42;
},
{
date = "2016-12-24";
name = Dicky;
result = W;
"results_id" = 19;
}
);
2 = (
{
date = "2017-01-25";
name = G;
result = W;
"results_id" = 38;
},
{
date = "2017-01-25";
name = G;
result = D;
"results_id" = 40;
},
{
date = "2017-01-21";
name = G;
result = L;
"results_id" = 34;
}
);
3 = (
{
date = "2017-01-31";
name = Sultan;
result = W;
"results_id" = 42;
},
{
date = "2017-01-15";
name = Sultan;
result = L;
"results_id" = 30;
}
);
}]
However I cannot seem to access the 1,2,3 parts of it...
let json = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String:AnyObject]
print (json!)
if let dict = json?["playerForm"] as? [String:AnyObject] {
print ("step 1")
if let arr = dict["1"] as? [[String:String]] {
print ("step 2")
self.leagueForm = arr.flatMap { Form($0) }
print (self.leagueForm)
print (self.leagueForm.count)
for i in 0..<self.leagueForm.count {
let form = self.leagueForm[i]
print (form.player_results!)
self.formGuide.append(form.player_results!)
}
print ("now")
print (self.formGuide)
self.resultsDisplay.results = self.formGuide
self.resultsDisplay.results = self.resultsDisplay.results.reversed()
self.resultsDisplay.displayResults()
}
}
With this code above it only gets as far as Step 1.
What am I doing wrong?
UPDATED WITH PROGRSS*
let json = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String:AnyObject]
print (json!)
if let dict = json?["playerForm"] as? [String:AnyObject] {
print ("step 1")
for (_ , value) in dict {
if let arr = value as? [[String:Any]] {
print(arr)
//your code
}
}
}
Custom Struct to define array:
struct Form {
var player_result: String?
var player_name: String?
var result_date: String?
var result_id: String?
init(_ dictionary: [String : Any]) {
self.player_result = dictionary["result"] as? String ?? ""
self.player_name = dictionary["name"] as? String ?? ""
result_date = dictionary["date"] as? String ?? ""
result_id = String(dictionary["results_id"] as? Int ?? 0)
}
}
Change your array type [[String:String]] to [[String:Any]] because it contains both String and Number as value.
if let arr = dict["1"] as? [[String:Any]] {
print(arr)
//your code
}
Note: You need to loop through the dict Dictionary because its each key having array.
for (_ , value) in dict {
if let arr = value as? [[String:Any]] {
print(arr)
//your code
}
}
I am trying to parse and get the values from this structure of JSON:
["mst_customer": 1, "data": {
0 = 2;
1 = 1;
2 = 1;
3 = "JAYSON TAMAYO";
4 = "581-113-113";
5 = 56;
6 = on;
7 = g;
8 = jayson;
9 = active;
"app_access" = on;
id = 2;
"mst_customer" = 1;
name = "Jayson Tamayo";
status = active;
territory = 1;
}, "status": OK, "staff_id": 2, "staff_name": Jayson Tamayo]
I use the following Swift code to get the values:
(data: Dictionary<String, AnyObject>, error: String?) -> Void in
if error != nil {
print(error)
} else {
if let feed = data["data"] as? NSDictionary ,let entries = data["data"] as? NSArray{
for elem: AnyObject in entries{
if let staff_name = elem["name"] as? String{
print(staff_name)
}
}
}
}
I am trying to get the name by using the keys name or staff_name. But I always get nil.
you want to access staff_name, which is not in "data" variable ... you can simply get that like
if error != nil {
print(error)
} else {
if let name = data["staff_name"] as? String{
print(name)
}
}
for elem: AnyObject in entries{
if let songName = elem["name"] as? String{
print(songName)
}
}
//replace above code with below code
if let songName : String = entries["name"] as? String{
print(songName)
}
I am trying to split (or explode) a string in Swift (1.2) using multiple delimiters, or seperators as Apple calls them.
My string looks like this:
KEY1=subKey1=value&subkey2=valueKEY2=subkey1=value&subkey2=valueKEY3=subKey1=value&subkey3=value
I have formatted it for easy reading:
KEY1=subKey1=value&subkey2=value
KEY2=subkey1=value&subkey2=value
KEY3=subKey1=value&subkey3=value
The uppercase "KEY" are predefined names.
I was trying to do this using:
var splittedString = string.componentsSeparatedByString("KEY1")
But as you can see, I can only do this with one KEY as the separator, so I am looking for something like this:
var splittedString = string.componentsSeperatedByStrings(["KEY1", "KEY2", "KEY3"])
So the result would be:
[
"KEY1" => "subKey1=value&subkey2=value",
"KEY2" => "subkey1=value&subkey2=value",
"KEY3" => "subkey1=value&subkey2=value"
]
Is there anything built into Swift 1.2 that I can use?
Or is there some kind of extension/library that can do this easily?
Thanks for your time, and have a great day!
One can also use the following approach to split a string with multiple delimiters in case keys are single characters:
//swift 4+
let stringData = "K01L02M03"
let res = stringData.components(separatedBy: CharacterSet(charactersIn: "KLM"))
//older swift syntax
let res = stringData.componentsSeparatedByCharactersInSet(NSCharacterSet(charactersInString: "KLM"));
res will contain ["01", "02", "03"]
If anyone knows any kind of special syntax to extend the approach to multiple characters per key you are welcome to suggest and to improve this answer
Swift 4.2 update to #vir us's answer:
let string = "dots.and-hyphens"
let array = string.components(separatedBy: CharacterSet(charactersIn: ".-"))
This isn't very efficient, but it should do the job:
import Foundation
extension String {
func componentsSeperatedByStrings(ss: [String]) -> [String] {
let inds = ss.flatMap { s in
self.rangeOfString(s).map { r in [r.startIndex, r.endIndex] } ?? []
}
let ended = [startIndex] + inds + [endIndex]
let chunks = stride(from: 0, to: ended.count, by: 2)
let bounds = map(chunks) { i in (ended[i], ended[i+1]) }
return bounds
.map { (s, e) in self[s..<e] }
.filter { sl in !sl.isEmpty }
}
}
"KEY1=subKey1=value&subkey2=valueKEY2=subkey1=value&subkey2=valueKEY3=subKey1=value&subkey3=value".componentsSeperatedByStrings(["KEY1", "KEY2", "KEY3"])
// ["=subKey1=value&subkey2=value", "=subkey1=value&subkey2=value", "=subKey1=value&subkey3=value"]
Or, if you wanted it in dictionary form:
import Foundation
extension String {
func componentsSeperatedByStrings(ss: [String]) -> [String:String] {
let maybeRanges = ss.map { s in self.rangeOfString(s) }
let inds = maybeRanges.flatMap { $0.map { r in [r.startIndex, r.endIndex] } ?? [] }
let ended = [startIndex] + inds + [endIndex]
let chunks = stride(from: 0, to: ended.count, by: 2)
let bounds = map(chunks) { i in (ended[i], ended[i+1]) }
let values = bounds
.map { (s, e) in self[s..<e] }
.filter { sl in !sl.isEmpty }
let keys = filter(zip(maybeRanges, ss)) { (r, _) in r != nil }
var result: [String:String] = [:]
for ((_, k), v) in zip(keys, values) { result[k] = v }
return result
}
}
"KEY1=subKey1=value&subkey2=valueKEY2=subkey1=value&subkey2=valueKEY3=subKey1=value&subkey3=value".componentsSeperatedByStrings(["KEY1", "KEY2", "KEY3"])
// ["KEY3": "=subKey1=value&subkey3=value", "KEY2": "=subkey1=value&subkey2=value", "KEY1": "=subKey1=value&subkey2=value"]
For Swift 2:
import Foundation
extension String {
func componentsSeperatedByStrings(ss: [String]) -> [String] {
let unshifted = ss
.flatMap { s in rangeOfString(s) }
.flatMap { r in [r.startIndex, r.endIndex] }
let inds = [startIndex] + unshifted + [endIndex]
return inds.startIndex
.stride(to: inds.endIndex, by: 2)
.map { i in (inds[i], inds[i+1]) }
.flatMap { (s, e) in s == e ? nil : self[s..<e] }
}
}
Swift 5:
extension String {
func components<T>(separatedBy separators: [T]) -> [String] where T : StringProtocol {
var result = [self]
for separator in separators {
result = result
.map { $0.components(separatedBy: separator)}
.flatMap { $0 }
}
return result
}
}
It's for the sack of nice and neat code, don't use it if you need something efficiently
Swift 2 for forward compatibility
Using a regular expression:
let string = "KEY1=subKey1=value&subkey2=valueKEY2=subkey1=value&subkey2=valueKEY3=subKey1=value&subkey3=value"
let nsString :NSString = string
let stringRange = NSMakeRange(0, string.utf16.count)
let pattern = "(KEY\\d)=([^=]+=[^&]+[^=]+?=[^K]+)"
var results = [String:String]()
do {
var regEx = try NSRegularExpression(pattern:pattern, options:[])
regEx.enumerateMatchesInString(string, options: [], range: stringRange) {
(result : NSTextCheckingResult?, _, _) in
if let result = result {
if result.numberOfRanges == 3 {
let key = nsString.substringWithRange(result.rangeAtIndex(1))
let value = nsString.substringWithRange(result.rangeAtIndex(2))
results[key] = value
}
}
}
}
catch {
print("Bad Pattern")
}
results: ["KEY3": "subKey1=value&subkey3=value", "KEY2": "subkey1=value&subkey2=value", "KEY1": "subKey1=value&subkey2=value"]
You could do it with regular expressions. The below snippet is a bit clumsy and not really fail-safe but it should give you an idea.
let string = "KEY1=subKey1=value&subkey2=valueKEY2=subkey1=value&subkey2=valueKEY3=subKey1=value&subkey3=value"
let re = NSRegularExpression(pattern: "(KEY1|KEY2|KEY3)=", options: nil, error: nil)!
let matches = re.matchesInString(string, options: nil,
range: NSMakeRange(0, count(string)))
var dict = [String: String]()
for (index, match) in enumerate(matches) {
let key = (string as NSString).substringWithRange(
NSMakeRange(match.range.location, match.range.length - 1))
let valueStart = match.range.location + match.range.length
let valueEnd = index < matches.count - 1 ? matches[index + 1].range.location
: count(string)
let value = (string as NSString).substringWithRange(
NSMakeRange(valueStart, valueEnd - valueStart))
dict[key] = value
}
The final value of dict is
[KEY3: subKey1=value&subkey3=value,
KEY2: subkey1=value&subkey2=value,
KEY1: subKey1=value&subkey2=value]