I have a dict(NSDictionary) that has the following data.
{
images = (
{
image = "image.jpg";
scores = (
{
"classifier_id" = "Adventure_Sport";
name = "Adventure_Sport";
score = "0.662678";
},
{
"classifier_id" = Climbing;
name = Climbing;
score = "0.639987";
},
{
"classifier_id" = Flower;
name = Flower;
score = "0.628092";
},
{
"classifier_id" = "Nature_Scene";
name = "Nature_Scene";
score = "0.627548";
},
{
"classifier_id" = Icicles;
name = Icicles;
score = "0.617094";
},
{
"classifier_id" = Volcano;
name = Volcano;
score = "0.604928";
},
{
"classifier_id" = Potatoes;
name = Potatoes;
score = "0.602799";
},
{
"classifier_id" = "Engine_Room";
name = "Engine_Room";
score = "0.595812";
},
{
"classifier_id" = Bobsledding;
name = Bobsledding;
score = "0.592521";
},
{
"classifier_id" = White;
name = White;
score = "0.587923";
},
{
"classifier_id" = Yellow;
name = Yellow;
score = "0.574398";
},
{
"classifier_id" = "Natural_Activity";
name = "Natural_Activity";
score = "0.54574";
},
{
"classifier_id" = Butterfly;
name = Butterfly;
score = "0.526803";
},
{
"classifier_id" = "Dish_Washer";
name = "Dish_Washer";
score = "0.513662";
},
{
"classifier_id" = Rainbow;
name = Rainbow;
score = "0.511032";
}
);
}
);
}
I am not able to figure out a way to access classfier_id in an array
Really need your help. Thanks. PS I have already tried dict["scores"] and dict["image.scores"]
Kindly help.. Thanks
You want
let classifier_ids = dict["scores"].map{$0["classifier_id"]}
If your containers are NSObjects rather than Swift Dictionaries and Arrays then you will need to add some type-casting, but that's the basic idea.
This code would be safer for non-typed collections:
var classifier_ids: [String?]
if let array = dict["scores"] as? [String:String]
{
let classifier_ids = array.map{$0["classifier_id"]}
}
That should give you an array of optionals, where a given entry will be nil if that entry in the array did not contain a "classifier_id" key/value pair.
Or if you want to skip entries that don't contain a "classifier_id" key/value pair:
var classifier_ids: [String]
if let array = dict["scores"] as? [String:String]
{
let classifier_ids = array.flatmap{$0["classifier_id"]}
}
Taking it a step at at time:
if let array = dict["images"] as? NSArray {
if let array2 = array[0]["scores"] as? NSArray {
if let ids = array2.valueForKey("classifier_id") as? [String] {
// use array of ids
print(ids)
}
}
}
or all in one shot:
if let ids = (dict["images"]?[0]["scores"])?.valueForKey("classifier_id") as? [String] {
// use array of ids
print(ids)
}
Related
I am having a hard time parsing JSON with Swift. I have written a function that make a get request to an api and retrieves the data as JSON and converts it into a dictionary. After that I am trying to use a tableViewController to set each title and subtitle from the values I received from the JSON. I am trying to set the title as the homeTeam and the subtitle as the awayTeam. I do not know much about Swift so I was hoping for some help.
Here is my JSON that is stored in a dictionary:
dictionary = ["scoreboard": {
gameScore = (
{
game = {
ID = 35119;
awayTeam = {
Abbreviation = ATL;
City = Atlanta;
ID = 91;
Name = Hawks;
};
date = "2017-04-07";
homeTeam = {
Abbreviation = CLE;
City = Cleveland;
ID = 86;
Name = Cavaliers;
};
location = "Quicken Loans Arena";
time = "7:30PM";
};
isCompleted = false;
isInProgress = false;
isUnplayed = true;
quarterSummary = "<null>";
},
{
game = {
ID = 35120;
awayTeam = {
Abbreviation = MIA;
City = Miami;
ID = 92;
Name = Heat;
};
date = "2017-04-07";
homeTeam = {
Abbreviation = TOR;
City = Toronto;
ID = 81;
Name = Raptors;
};
location = "Air Canada Centre";
time = "7:30PM";
};
isCompleted = false;
isInProgress = false;
isUnplayed = true;
quarterSummary = "<null>";
},
{
game = {
ID = 35121;
awayTeam = {
Abbreviation = NYK;
City = "New York";
ID = 83;
Name = Knicks;
};
date = "2017-04-07";
homeTeam = {
Abbreviation = MEM;
City = Memphis;
ID = 107;
Name = Grizzlies;
};
location = "FedEx Forum";
time = "8:00PM";
};
isCompleted = false;
isInProgress = false;
isUnplayed = true;
quarterSummary = "<null>";
},
{
game = {
ID = 35122;
awayTeam = {
Abbreviation = DET;
City = Detroit;
ID = 88;
Name = Pistons;
};
date = "2017-04-07";
homeTeam = {
Abbreviation = HOU;
City = Houston;
ID = 109;
Name = Rockets;
};
location = "Toyota Center";
time = "8:00PM";
};
isCompleted = false;
isInProgress = false;
isUnplayed = true;
quarterSummary = "<null>";
},
{
game = {
ID = 35123;
awayTeam = {
Abbreviation = SAS;
City = "San Antonio";
ID = 106;
Name = Spurs;
};
date = "2017-04-07";
homeTeam = {
Abbreviation = DAL;
City = Dallas;
ID = 108;
Name = Mavericks;
};
location = "American Airlines Center";
time = "8:30PM";
};
isCompleted = false;
isInProgress = false;
isUnplayed = true;
quarterSummary = "<null>";
},
{
game = {
ID = 35124;
awayTeam = {
Abbreviation = NOP;
City = "New Orleans";
ID = 110;
Name = Pelicans;
};
date = "2017-04-07";
homeTeam = {
Abbreviation = DEN;
City = Denver;
ID = 99;
Name = Nuggets;
};
location = "Pepsi Center";
time = "9:00PM";
};
isCompleted = false;
isInProgress = false;
isUnplayed = true;
quarterSummary = "<null>";
},
{
game = {
ID = 35125;
awayTeam = {
Abbreviation = MIN;
City = Minnesota;
ID = 100;
Name = Timberwolves;
};
date = "2017-04-07";
homeTeam = {
Abbreviation = UTA;
City = Utah;
ID = 98;
Name = Jazz;
};
location = "Vivint Smart Home Arena";
time = "9:00PM";
};
isCompleted = false;
isInProgress = false;
isUnplayed = true;
quarterSummary = "<null>";
},
{
game = {
ID = 35126;
awayTeam = {
Abbreviation = OKL;
City = "Oklahoma City";
ID = 96;
Name = Thunder;
};
date = "2017-04-07";
homeTeam = {
Abbreviation = PHX;
City = Phoenix;
ID = 104;
Name = Suns;
};
location = "Talking Stick Resort Arena";
time = "10:00PM";
};
isCompleted = false;
isInProgress = false;
isUnplayed = true;
quarterSummary = "<null>";
},
{
game = {
ID = 35127;
awayTeam = {
Abbreviation = SAC;
City = Sacramento;
ID = 103;
Name = Kings;
};
date = "2017-04-07";
homeTeam = {
Abbreviation = LAL;
City = "Los Angeles";
ID = 105;
Name = Lakers;
};
location = "Staples Center";
time = "10:30PM";
};
isCompleted = false;
isInProgress = false;
isUnplayed = true;
quarterSummary = "<null>";
}
);
lastUpdatedOn = "<null>";
}]
Here is what I have currently for setting my title and subtitle in Swift:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "NBAScore", for: indexPath)
// Configure the cell...
if let scoreBoard = d.dictionary["scoreboard"] as? [String:AnyObject]
{
if let gameScore = scoreBoard["gameScore"] as? [String:AnyObject]
{
if let game = gameScore["game"] as? [String:AnyObject]
{
if let awayTeam = game["awayTeam"] as? String
{
cell.textLabel?.text = awayTeam }
}
}
}
return cell
}
Best will be to create a Struct add variable's for the properties you need after that make an array from that struct parse your array of json using a for loop and append them to the newly array you have created then you can access those properties using dot notation inside your cellForRow function
Use the below code to get the team name -
if let scoreBoard = d.dictionary["scoreboard"] as? [String:AnyObject]
{
if let gameScore = scoreBoard["gameScore"] as? [String:AnyObject]
{
if let game = gameScore["game"] as? [String:AnyObject]
{
if let awayTeam = game["awayTeam"] as? [String: AnyObject] {
if let teamName = awayTeam["Name"] as? String {
cell.textLabel?.text = teamName
}
}
}
}
}
For that purpose I would use some library that was build to parse JSON dictionaries to some model objects as it's a good practice. E.g. I would recommend Marshal as it's lightweight and easy to use.
You just create a struct or any other Swift structure and then you call Marshal. Later on you use those mapped objects in your tableView dataSource.
Your 'gameScore' object is an array not a dictionary type ([String:AnyObject]). My mistake that i didn't check the json object properly.
First create an array and store all the team name in that array. For Example, I am storing all the awayteam name for now in an array. Check the below code. I didn't run the below source code in my end, Since your json has problem. It's not a valid json data. There is formatting issue. But this below code will work.
let awayTeamArr = NSMutableArray()
if let scoreBoard = d.dictionary["scoreboard"] as? [String:AnyObject] {
if let gameScore = scoreBoard["gameScore"] as? NSArray {
for gameScoreObj in gameScore {
if let gameObj = gameScoreObj as [String: AnyObject] {
if let game = gameObj["game"] as? [String:AnyObject] {
if let awayTeam = game["awayTeam"] as? [String: AnyObject] {
if let teamName = awayTeam["Name"] as? String {
awayTeam.add(teamName)
}
}
}
}
}
}
}
Then in your tableView delegate method for each cell display the object of that specific index of 'awayTeamArr' object. If this answer worked then make the question as completed.
I was able to figure out an answer to my own question. The "gameScore" key of the dictionary was giving me trouble because I was type casting it incorrectly. It was an Array<[String:Any]> not a dictionary.
func parseJSON(){
var s = nbaScore()
var i = 0
if let scoreBoard = d.dictionary["scoreboard"] as? [String:AnyObject]
{
// Could check the lastUpdattedOn date before doing the following:
if let gameScore = scoreBoard["gameScore"] as? Array<[String:Any]>
{ //Loop for # of games
//while gameScore[i]["game"] as? [String:Any] != nil
while i < gameScore.count
//for _ in (gameScore[0]["game"] as? [String:Any])!
{
// An array of dictionaries
if let game = gameScore[i]["game"] as? [String:Any]
{
s.gameTime = (game["time"] as? String)!
if let awayTeam = game["awayTeam"] as? [String:Any]
{
s.awayTeamCity = (awayTeam["City"] as? String)!
s.awayTeamName = (awayTeam["Name"] as? String)!
}
if let homeTeam = game["homeTeam"] as? [String:Any]
{
s.homeTeamCity = (homeTeam["City"] as? String)!
s.homeTeamName = (homeTeam["Name"] as? String)!
}
}
if let isUnplayed = gameScore[i]["isUnplayed"] as? String
{
s.isUnplayed = isUnplayed
}
if let isInProgress = gameScore[i]["isInProgress"] as? String
{
s.isInProgress = isInProgress
}
if let isCompleted = gameScore[i]["isCompleted"] as? String
{
s.isCompleted = isCompleted
}
if let awayScore = gameScore[i]["awayScore"] as? String
{
s.awayTeamScore = awayScore
}
if let homeScore = gameScore[i]["homeScore"] as? String
{
s.homeTeamScore = homeScore
}
i += 1
scores.append(s)
s.clearData()
gamesCount += 1
}
}
}
}
parsed is an NsDictionary and I am pulling the balances out of it via
if let findbalances: AnyObject = parsed["balances"]
which gives me a list of balances in AnyObject format
(
{
"available_amount" = 133519;
currency = AUD;
},
{
"available_amount" = 7854;
currency = CAD;
},
{
"available_amount" = 88581;
currency = EUR;
},
{
"available_amount" = 0;
currency = GBP;
},
{
"available_amount" = 63618;
currency = INR;
},
{
"available_amount" = 375;
currency = NZD;
},
{
"available_amount" = 0;
currency = TRY;
},
{
"available_amount" = 2918958;
currency = USD;
}
)
I know that
let whatCurrency = (findbalances[7]["currency"] as! String)
=USD But how do I find that value [7] if the amount of objects changes?
I want to match on USD
I tried
let defaultcurr = "USD"
let findUSD = findbalances.indexOfObject(defaultcurr)
but that gave me 9223372036854775807
How do I just find 7
9223372036854775807 is NSNotFound.
You can use a closure as argument of indexOf
let defaultcurr = "USD"
let findUSDIndex = findbalances.indexOf { ($0["currency"] as! String) == defaultcurr }
Or you can filter the entire row
let findUSD = findbalances.filter { ($0["currency"] as! String) == defaultcurr }.first
indexOfObject seems to be using NSArray. Don't do that. Use Swift native Array and cast your collection object to [[String:AnyObject]] :
if let findbalances = parsed["balances"] as? [[String:AnyObject]] { ...
I have one array with dictionary.
Now i want to get index number of object with particular key value.
Like key = "xyz" and value = "abc".
I need index of object having above matching in dictionary.
{
Id = 20085;
IsNew = 1;
Title = Circular;
},
{
Id = 20088;
IsNew = 0;
Title = Query;
},
{
Id = 20099;
IsNew = 1;
Title = Blog;
},
{
Id = 20104;
IsNew = 1;
Title = News;
},
{
Id = 20172;
IsNew = 1;
Title = AssignTask;
},
{
Id = 20183;
IsNew = 1;
Title = Gallery;
},
{
Id = 20204;
IsNew = 1;
Title = Poll;
},
{
Id = 20093;
IsNew = 1;
Title = Assignment;
},
{
Id = 20209;
IsNew = 1;
Title = Activity;
},
{
Id = 20130;
IsNew = 1;
Title = Behaviour;
},
{
Id = 20180;
IsNew = 1;
Title = Result;
}
now i need index of object with having key = "Title" and value = "result"
You can use indexOf(_:) for this:
let index = array.indexOf{ $0["key"] == value }
In Swift 3.0, it's been renamed to index(Where:):
let index = array.index{ $0["key"] == value }
You can see this in action here.
Here is what you should be doing after using a json parser
let array:NSArray = [
[
"Id": 20130,
"IsNew": 1,
"Title":"Behaviour"
],
[
"Id": 20180,
"IsNew": 1,
"Title":"Result"
]]
let k = array as Array
let index = k.indexOf {
if let dic = $0 as? Dictionary<String,AnyObject> {
if let value = dic["Title"] as? String
where value == "Result"{
return true
}
}
return false
}
print(index) // index
I'd start with mapping the id values to an array, then getting the index of the id you're looking for.
func getIndexOf(itemID: Int) -> Int {
//Map out all the ids from the array of dictionaries into an array of Integers
let keysArray = dictionaries.map { (dictionary) -> Int in
return dictionary.value(forKey: "Id")
}
//Find the index of the id you passed to the functions
return keysArray.index(of: itemID)
}
other mainstream way to do this
func getIndex(of key: String, for value: String, in dictionary : [[String: Any]]) -> Int{
var count = 0
for dictElement in dictionary{
if dictElement.keys.contains(key) && dictElement[key] as! String == value{
return count
}
else{
count = count + 1
}
}
return -1
}
var sampleDict : [[String:Any]] = [
[
"Id" : 20130,
"IsNew" : 1,
"Title" : "Behaviour"
],
[
"Id" : 20130,
"IsNew" : 1,
"Title" : "Result"
],
]
let index = getIndex(of: "Title", for: "Result", in: sampleDict)
print(index)
This will print 1.
This answer is for the Swift 5.2 and above versions.
arr.append(["Title":titleName,"ID":1,"Result":true])
arr.append(["Title":titleName,"ID":2,"Result":true])
arr.append(["Title":titleName,"ID":3,"Result":true])
arr.append(["Title":titleName,"ID":4,"Result":true])
This is an array of dictionary format. And if you want to find an index of an object where ID == 3
func findIndex(Id : Int ) -> Int? {
guard let index = arr.firstIndex(where: {
if let dic = $0 as? Dictionary<String,AnyObject> {
if let value = dic["ID"] as? Int, value == Id {
return true
}
}
return false
}) else { return nil }
return index
}
let myIndex = findIndex(3)
self.arr.insert( ["Title":titleName,"ID":10,"Result":true]) at: myIndex)
I am trying to read info from plist, (PetList.plist) but I don't know why it failed. The variable path is correct, however myDict is nil, the else part is executed. What I want to do is load info form plist, then assign values to pets array.
var pets = Pet
func loadGameData() {
let path = NSBundle.mainBundle().pathForResource("PetList", ofType: "plist")
let myDict = NSDictionary(contentsOfFile: path!)
if let dict = myDict {
//loading values
for i in 0..<pets.count {
pets[i].petName = dict.objectForKey("petName")!.absoluteString!
pets[i].health = dict.objectForKey("health")!.absoluteString!
pets[i].experience = dict.objectForKey("experience")!.absoluteString!
pets[i].hungry = dict.objectForKey("hungry")!.absoluteString!
pets[i].energy = dict.objectForKey("energy")!.absoluteString!
pets[i].level = dict.objectForKey("level")!.absoluteString!
pets[i].status = dict.objectForKey("status")!.absoluteString!
pets[i].searchKey = dict.objectForKey("searchKey")!.absoluteString!
pets[i].cleanliness = dict.objectForKey("cleanliness")!.absoluteString!
pets[i].isChoosed = dict.objectForKey("isChoosed")!.absoluteString!
pets[i].skill = dict.objectForKey("skill")!.absoluteString!
pets[i].imageName = dict.objectForKey("imageName")!.absoluteString!
}
} else {
print("WARNING: Couldn't create dictionary from PetList.plist! Default values will be used!")
}
}
There are a few issues.
The top level object is an array
absoluteString will cause an compiler error.
There must be a Pet struct or class to create instances from the array.
Something like this
struct Pet {
var petName = "", health = "", experience = "", hungry = ""
var energy = "", level = "", status = "", searchKey = ""
var cleanliness = "", isChoosed = "", skill = "", imageName = ""
}
var pets = [Pet]()
func loadGameData() {
let path = NSBundle.mainBundle().pathForResource("PetList", ofType: "plist")
if let myArray = NSArray(contentsOfFile: path!) as? [[String:String]] {
//loading values
for anItem in myArray {
var pet = Pet()
pet.petName = anItem["petName"]!
pet.health = anItem["health"]!
pet.experience = anItem["experience"]!
pet.hungry = anItem["hungry"]!
pet.energy = anItem["energy"]!
pet.level = anItem["level"]!
pet.status = anItem["status"]!
pet.searchKey = anItem["searchKey"]!
pet.cleanliness = anItem["cleanliness"]!
pet.isChoosed = anItem["isChoosed"]!
pet.skill = anItem["skill"]!
pet.imageName = anItem["imageName"]!
pets.append(pet)
}
} else {
print("WARNING: Couldn't create array from PetList.plist! Default values will be used!")
}
}
The top-level node of PetList.plist is an array, not a dictionary, which is why it's not loading.
{
QueueId = 27;
SongId = 38;
artWorkURL = "<null>";
duration = 58258;
"stream_url" = "https://api.soundcloud.com/tracks/233301835/stream";
title = Magenta;
trackID = 233301835;
userAvatar = "https://i1.sndcdn.com/avatars-000188204071-llusgk-large.jpg";
userName = Agiv;
},
{
QueueId = 27;
SongId = 39;
artWorkURL = "<null>";
duration = 79000;
"stream_url" = "https://api.soundcloud.com/tracks/233301833/stream";
title = Nino;
trackID = 233301833;
userAvatar = "https://i1.sndcdn.com/avatars-000157591669-eva3mg-large.jpg";
userName = "SWR Umwelt und Ern\U00e4hrung";
}
My array of dictionary format is as above and multiple tracks i want to check 27 is already there or not ?
You can do this with the filter function
let queueID27Exists = !array.filter({$0["QueueId"] as? Int == 27}).isEmpty
This answer is for your previous JSON object!
if let results : NSDictionary = post.objectForKey("data") as? NSDictionary {
let array:NSArray = (results.valueForKey("track") as! NSArray)
if "25" == array[0].valueForKey("trackID") as? String {
NSLog("YES")
} else {
NSLog("NO")
}
}
var found = false
for (_, data) in post {
let track = data["track"]
if track["trackID"] == "25" {
found = true
}