I have an NSDictionary like this :
{
"name": "Hayagreeva", //String
"age": 3, //Number
"subjects": { //Array
"rhymes": { //Dictionary 1
"test1": 10,
"test2": 20,
"test3": 30
},
"games": { //Dictionary 2
"test1": 40,
"test2": 50,
"test3": 60
},
"crayoning": { //Dictionary 3
"test1": 70,
"test2": 80,
"test3": 90
}
},
"date": "2008-02-16T10:06:00Z" //Date
}
Now I need to replace the value for key subjects > games > test1 from 40 to value 60. I know the lenghty process of taking another dictionary objects and create a similar dictionary but that process is time consuming and may be a wrong strategy. I have searched many questions also here but all of them have the way to remove the key for the first level dictionary (like removing key "subjects" in the above code). So I want to know if there is an easy and efficient way to update the value for key in an inner level as I need to execute this process at many situations in my current project. Thanks in advance.
Edit : I also tried something like
[dict removeValueForKey:#"subjects.games.test1"];
But that doesn't work. I hope that this line helps you to understand the desired functionality by me.
If that structure is set in stone and will not change then it's as simple as:
NSDictionary *topLevelDict = ...;
topLevelDict[#"subjects"][#"games"] = #{
#"test1" : #(60),
#"test2" : #(50),
#"test3" : #(60)
};
Dictionaries of dictionaries are a pain to manipulate and it's always better to create a custom model object that allows easier manipulation, validation with the additional benefit of domain-specific functionality like serialization etc.
Related
Cosider an API which reply is always of this structure:
{
"pagination": {
"limit": int,
"offset": int,
"count": int,
"total": int
},
"data": [
{...some obj...}
]
}
So payloads differ only in structure of data objects.
Ideally I'd like to tell F# that all types built from samples have some common part - pagination info, so I can have one generic method which reads all pages.
Is it possible, or do I have to extract pagination object and data array separately with two type providers? I see the benefit of having one provider per response body as it supports reading data from the stream.
I would define two different provided types, one for parsing the pagination data and one for parsing the actual data, i.e. something like this:
type Pagination = JsonProvider<"""{
"pagination": { "limit": 1, "offset": 2,
"count": 3, "total": 4 }
}""">
type OneDataType = JsonProvider<"""{
"data": [ {"a": 1} ]
}""">
If you want to avoid parsing the same JSON file twice (e.g. by calling Pagination.Parse and OneDataType.Parse on the same string), you can actually just parse the data once and then pass the parsed JsonValue to the other type:
let odt = OneDataType.Load("/some/file")
let pg = Pagination.Root(odt.JsonValue)
pg.Pagination.Count
If you wanted to do this with a single provided type, then you could define multiple different fields for the multiple different types of data - but you'd have to name those differently. You'd then need to do some fiddling to read the data correctly. I would not do this, because I find it confusing, but it would look something like this:
type AnyData = JsonProvider<"""{
"pagination": { "limit": 1, "offset": 2,
"count": 3, "total": 4 },
"data": [],
"one_data_type": [ {"a":1} ],
"another_data_type": [ {"b":"xx" }]
}""">
let a = AnyData.Load("/some/file")
// Access pagination data
a.Pagination
// Access data as if it was OneDataType
let oneData = [| for d in a.Data ->
AnyData.OneDataType(d.JsonValue) |]
So if I have a dictionary like the following:
{
"banners": [
{
"imageUrl": "www.google.com",
"destination": "home",
"position": 1
},
{
"imageUrl": "www.reddit.com",
"destination": "work",
"position": 2
},
{
"imageUrl": "www.imgur.com",
"destination": "play",
"position": 3
}
]
}
is there a way for me to say, "Get me the dictionary object where the value for the key 'position' = 3 without using a for loop?
Let's think about it. Oooh, there are a lot of ways! It's amazing what looking for just a moment at the documentation will tell you.
What you have as the value of the banners key is an array of dictionaries. So what you are looking for is an NSArray method. An NSArray method such as filteredArrayUsingPredicate:!
So you can write an NSPredicate that describes position as being equal to 3, and you'll get back an NSArray of all the dictionaries where that is true (in this case, an array of one dictionary).
Oh, here's another possibility: indexOfObjectPassingTest:. With this, you supply a block that specifies that the dictionary's position is 3, and you'll get back the index of that dictionary within this array (namely 2 in this case).
I could go on and on, but wouldn't it be better for you to learn to read the documentation for yourself? Here it is.
I've got a JSON as below.
odds: {
0501: {
x: 2.75,
description: "a"
},
0502: {
x: 3.25,
description: "b"
},
0513: {
x: 3.5,
description: "c"
},
0503: {
x: 3.5,
description: "d"
},
0505: {
x: 7.5,
description: "e"
},
0504: {
x: 7.5,
description: "f"
},
0512: {
x: 10,
description: "g"
}
}
This hash comes from HTTP response as I want to show but the thing that I use JSONModel to map it and there is only way to map that NSDictionary. When map this JSON to NSDictionary (as you can guess) this an unordered and sequence of data comes up mixed.
So, how to map this JSON, without broke up its sequence using JSONModel and NSDictionary ?
NSDictionary is inherently unordered:
Are keys and values in an NSDictionary ordered?
If you want to preserve the order of key-value entries, you need to use a data structure other than NSDictionary. Any library that passes your data through an NSDictionary cannot preserve the order.
Something I've done in this situation is to sort the dictionary keys in a separate array, in addition to the dictionary. Use the ordered key array to determine how to display your dictionary values.
Dictionaries can not be sorted, but as your JSON seems to be an array of objects, iterate thru your resulting NSDictionary with for...in and add the elements to a mutable array.
Afterwards sort the resulting array using .sortInPlace by comparing the x-value.
I have a dictionary like <String,Loto> and Loto is object like below;
Loto:
{
"success": true,
"data": {
"oid": "64kbbqi8dbxygb00",
"hafta": 961,
"buyukIkramiyeKazananIl": "",
"cekilisTarihi": "11/04/2015",
"cekilisTuru": "SAYISAL_LOTO",
"rakamlar": "03#02#48#16#15#08",
"rakamlarNumaraSirasi": "02 - 03 - 08 - 15 - 16 - 48",
"devretti": false,
"devirSayisi": 0,
"bilenKisiler": [
{
"oid": "64kbbxi8dbxyg403",
"kisiBasinaDusenIkramiye": 7.35,
"kisiSayisi": 185712,
"tur": "$3_BILEN"
},
{
"oid": "64kbbxi8dbxyg402",
"kisiBasinaDusenIkramiye": 53.05,
"kisiSayisi": 9146,
"tur": "$4_BILEN"
},
{
"oid": "64kbbxi8dbxyg401",
"kisiBasinaDusenIkramiye": 4532.2,
"kisiSayisi": 142,
"tur": "$5_BILEN"
},
{
"oid": "64kbbxi8dbxyg400",
"kisiBasinaDusenIkramiye": 1528438.75,
"kisiSayisi": 1,
"tur": "$6_BILEN"
}
],
"buyukIkrKazananIlIlceler": [
{
"il": "10",
"ilView": "BALIKESÄ°R",
"ilce": "01001",
"ilceView": "AYVALIK"
}
],
"kibrisHasilati": 51127,
"devirTutari": 0.09,
"kolonSayisi": 10537872,
"kdv": 1599672.97,
"toplamHasilat": 10537872,
"hasilat": 8938199.03,
"sov": 893819.9,
"ikramiyeEH": 8044379.129999999,
"buyukIkramiye": 1528432.03,
"haftayaDevredenTutar": 0
}
}
So my dictionary like <"11042015",Loto> and i want to sort this dictionary by "hafta" property of loto object.
How can i do this? Please help me!
If Loto is an object with a hafta property, you can sort your dictionary by passing it into the sorted function, along with a closure that tells it how to order the entries:
sorted(dict) { $0.1.hafta < $1.1.hafta }
($0.1 and $1.1 because dictionaries present as a sequence of key/value pairs - you want to sort by a property of the value i.e. tuple entry 1)
Note, this will give you back a sorted array, of type [(String,Loto)] pairs, rather than a dictionary (as Swift dictionaries are unordered).
(if Loto is not really an object but rather another dictionary, you might need to do {$0.1["hafta"] < $1.1["hafta"]} - it really depends on how you’re holding your data - the good news is you don’t need to worry about optionals, since they can be compared with <)
If you don’t need the keys, just sort the values:
sorted(dict.values) { $0.hafta < $1.hafta }
which will give you back a sorted array of type [Loto]
Dictionaries are not ordered. What you need is to convert it to array, and then sort it. So something like this.
let lotoArray = lotoDictionary.allObjects as [Loto]
lotoArray.sort { $0.hafta < $1.hafta }
You can't. The keys of a dictionary are not sorted. You can get an array of the values and sort that array.
JSON:
{
"projects":[
{
"id":113,
"name":"Mobile app Android",
"description":"",
"created_on":"2014-10-03T16:53:56+02:00",
"updated_on":"2014-12-03T16:59:45+01:00"
},
{
"id":142,
"name":"Mobile app iOS",
"created_on":"2014-12-11T18:30:55+01:00",
"updated_on":"2014-12-11T18:30:55+01:00"
},
{
"id":52,
"name":"Test project",
"identifier":"grafikr",
"description":"",
"created_on":"2013-10-14T17:21:33+02:00",
"updated_on":"2014-10-10T17:40:47+02:00"
},
{
"id":37,
"name":"Sample project",
"identifier":"grafikf",
"description":"",
"created_on":"2013-09-18T16:31:25+02:00",
"updated_on":"2013-09-26T13:11:58+02:00"
}
],
"total_count":4,
"offset":0,
"limit":25
}
It is easy to access for example name of the first project (with name Mobile app Android) by var name = json["projects"][0]["name"].stringValue
But how do I access all names in SwiftyJSON? If I make a variable var projects = json["projects"], it gives me:
[
{
"id" : 113,
"created_on" : "2014-10-03T16:53:56+02:00",
"name" : "Mobile app Android",
"description" : "",
"updated_on" : "2014-12-03T16:59:45+01:00"
},
...
Now I don't have a problem with making a NSDictionary from data anymore, but this drives me crazy.
There's a lot going on in your code sample—perhaps too much to be addressed by a single Stack Overflow question / answer.
I would strongly recommend going back to Apple's resources for Swift and iOS application patterns. Topics to revisit would include synchronous versus asynchronous programming, authentication, and using data sources with table views.
This should probably work. Your json also contains "total_count", which looking at it, I assume that's the count of the number of projects. Pull that count out, loop over till the count and fetch the name.
var names = [String]()
let count = json["total_count"].int
for index in 0..<count {
let name = json["projects"][index]["name"].string
names.append(name)
}
Why not use SwiftyJSON the Swifty way???
Try this:
let names = json["projects"].arrayValue.map {
$0["name"].stringValue
}