Add element to a complex nested collection in swift - ios

I'm stuck practicing collections in Swift. Actually, I storing data from an online JSON source into dictionaries/arrays. I'm trying to add a new element to the following collection:
testDict1: Dictionary<String,Dictionary<Int,Dictionary<String, AnyObject>>>
I initialized it with the following elements (it could have been an empty array):
testDict1 = ["fireMagic":[
0:["name":"Basic attack","damage":100],
1:["name":"Super attack","damage":200, "lvlReq": 20],
2:["name":"Mega attack","damage":400, "lvlReq": 40]]]
I would like to "update" data within testDict1 (replace and add a new row if needed) from another array such as:
testDict1 = ["fireMagic":[
0:["name":"Basic attack","damage":100],
1:["name":"Super attack","damage":200, "lvlReq": 20],
2:["name":"Mega attack","damage":400, "lvlReq": 40]
3:["name":"Insane attack","damage":1000, "lvlReq": 60]]]
QUESTION 1
How can I append the element below to testDict1:
3:["name":"Insane attack","damage":1000, "lvlReq": 60] //with "FireMagic" as a key.
I'm facing different errors and I can't make it work. I'm sure it must be more complex than the ways I tried and you may have the solution to end my pain :)
QUESTION 2
How do I do if I need to add other powers such as "WaterMagic" with the same structure as "FireMagic" in testDict1.
testDict1 = ["fireMagic":[
0:["name":"Basic attack","damage":100],
1:["...":"...","...":"..."]],
["waterMagic":[
0:["name":"Basic attack","damage":100]]
Thank you in advance for your help in my learning quest!

Q1:
Unsafe:
testDict1["fireMagic"]![3] = ["name":"Insane attack","damage":1000, "lvlReq": 60]
Safe:
if let _ = testDict1["fireMagic"] {
testDict1["fireMagic"]![3] = ["name":"Insane attack","damage":1000, "lvlReq": 60]
}
Safe and simple (thanks #dfri):
testDict1["fireMagic"]?[3] = ["name":"Insane attack","damage":1000, "lvlReq": 60]
Q2:
testDict1["waterMagic"] = [0:["name":"Test attack","damage":100]]
But I would suggest using arrays, enums and structs instead of dictionaries, it's much simpler to handle, and it's also more safe:
enum MagicType {
case Water
case Fire
}
struct Magic {
let magic: MagicType
let name: String
let damage: Int
let lvlReq: Int?
}
Create an array of objects:
var fireMagics = [Magic(magic: .Fire, name: "Basic attack", damage: 100, lvlReq: nil), Magic(magic: .Fire, name: "Super attack", damage: 200, lvlReq: 20), Magic(magic: .Fire, name: "Mega attack", damage: 100, lvlReq: 40)]
Access the objects in the array by index:
fireMagics[0]
fireMagics[1]
fireMagics[2]
etc.
Add an object to the array:
fireMagics.append(Magic(magic: .Fire, name: "Insane attack", damage: 1000, lvlReq: 60))
Create a different type of Magic object:
var waterMagics = [Magic(magic: .Water, name: "Test attack", damage: 100, lvlReq: nil)]

Related

LUA and table data - finding data in a nested loop

I have the following table
scavenging =
{
{
type = "Greenskin|16",
fast_levelup = 20, --Number of levels with 75% chance to level up after required level
normal_levelup = 40, --Number of levels with 50% chance to level up after fast_levelup + required level
slow_levelup = 40, --Number of levels with 25% chance
drops = --Drops
{
{items = {"Linen", "Bolt of Linen", "Coarse Thread", "Feather", "Cotton"}, droprates = {60, 10, 10, 10, 2}},
},
},
}
This is one data value in a series. I use
function scavenge_meta(scavenge_name)
for _, meta in pairs(scavenging) do
if string.match(meta.type, scavenge_name) then
return meta
end
end
end
to pull the needed data. The question is, is there an easy way to get to the droprates value without having to do a few for (pairs)? Right now for example I can use:
local founditem = scavenge_meta("Greenskin|16")
And this works, and then I can use founditem.fast_levelup etc. I was hoping to access the drops table with founditem.drops.items for example, but this doesn't work, I need to do a pairs(founditem.drops) then pairs(valuefound.items) /etc.
Maybe there is a better way of doing this?
if you can change the table then do:
scavenging =
{
["Greenskin|16"] = {
type = "Greenskin|16",
fast_levelup = 20,
normal_levelup = 40,
slow_levelup = 40,
drops =
{
{items = {"Linen", "Bolt of Linen", "Coarse Thread", "Feather", "Cotton"}, droprates = {60, 10, 10, 10, 2}},
},
},
}
and get data directly by index
print(scavenging["Greenskin|16"].fast_levelup)
otherwise, just by searching as you did.

Use max_by in Ruby to find the key for the maximum number in a hash

I need to find the category, within an array, that holds the "largest" weight. I define the weights in an environment variable:
CATEGORY_WEIGHTS = {
"small_standard": 0,
"large_standard": 1,
"small_oversize": 2,
"medium_oversize": 3,
"large_oversize": 4
}
In this example, the "largest" weighted category would be large_oversize.
The array that I'm checking looks like this:
categories = [
"small_oversize",
"large_standard",
"small_standard",
"large_oversize"
]
But when I do this, it doesn't return the correct value:
max_category = categories.max_by{ |cat| CATEGORY_WEIGHTS[cat] }
It returns small_oversize instead of large_oversize.
Where did I go astray?
You're using symbols in the hash, but you're trying to access it with strings. Change it to:
max_category = categories.max_by{|cat| CATEGORY_WEIGHTS[cat.to_sym]}
And here is how you can do it simpler:
category_weights = {
small_standard: 0,
large_standard: 1,
small_oversize: 2,
medium_oversize: 3,
large_oversize: 4
}
category = category_weights.max_by{|c, w| w}[0]

Create multidimentional array in swift with different datatypes

this is my first question here so forgive me if it is not very clear.
I am trying to create an array in swift that will store either arrays of arrays or an integer number.
The array is supposed to be a simple representation of the data I will be using which is basically a tree kind of data structure like so...
Array = [ [[ [2, 3] ], [ 1, 4 ], [ 2 ]],
[ 2 ], [[2, 5], [6, 1] ], 3 ]
In overall the arrays are the branches and the integers are the leaves
I've tried declaring them as optionals like so
var test2 = [[[Int]?]?]()
Or using typedef's but I still can't get it to work.
Also, it should be possible to add new leaves to any of the arrays
Here is a solution based on enum, first declare the enum:
enum Node
{
case leaf(Int)
case branch([Node])
}
You can now write things such as:
let x = Node.leaf(42)
let y = Node.branch([Node.leaf(42), Node.leaf(24)])
However this is going to become laborious very quickly. Fortunately Swift allows conversions from literals, so we add:
extension Node : ExpressibleByIntegerLiteral
{
init(integerLiteral value: Int)
{
self = .leaf(value)
}
}
extension Node : ExpressibleByArrayLiteral
{
init(arrayLiteral elements: Node...)
{
self = .branch(elements)
}
}
And with those added we can now write the above two let statements as:
let x : Node = 42
let y : Node = [42, 24]
which is nicer. However if we print(y) we get:
branch([Node.leaf(42), Node.leaf(24)])
If you wish to pretty print that you can add:
extension Node : CustomStringConvertible
{
var description : String
{
switch self
{
case .leaf(let value):
return value.description
case .branch(let branches):
return branches.description
}
}
}
And now print(y) gives you:
[42, 24]
Finally your example:
let w : Node = [[[[2, 3]], [1, 4], [2]], [2], [[2, 5], [6, 1]], 3]
which prints as:
[[[[2, 3]], [1, 4], [2]], [2], [[2, 5], [6, 1]], 3]
You'll want to complete the enum type, with predicates such as isLeaf etc., but that is the basic idea.
HTH

casting a List<object> into NancyFx response

I am trying to build an Nancy OData support app using LinqToQuerystring. I got below sample code. it is working for any query url like:
http:/test/?$filter=Recommended eq true
Get["/test"] = _ =>
{
var dict = (IDictionary)Request.Query.ToDictionary();
new List<Movie>
{
new Movie
{
Title = "Matrix (The)",
ReleaseDate = new DateTime(1999, 3, 31),
DurationInMinutes = 136,
MetaScore = 73,
Director = "Wachowski Brothers",
Recommended = true
},
new Movie
{
Title = "There and Back Again, An Unexpected Journey",
ReleaseDate = new DateTime(2012, 12, 14),
DurationInMinutes = 169,
MetaScore = 58,
Director = "Peter Jackson",
Recommended = false
}
}.AsQueryable()
.LinqToQuerystring(dict);
return dict;
}
You can solve this by calling ToDictionary first.
i.e
var dict = (IDictionary<string, object>) Request.Query.ToDictionary();
...
.LinqToQuerystring(dict);
This is probably because of the way LinqToQuerystring handles Dictionary under the hood, outputting them in an intermediate window causes:
(IDictionary<string, object>) Request.Query
{Nancy.DynamicDictionary}
[Nancy.DynamicDictionary]: {Nancy.DynamicDictionary}
Keys: Count = 2
Values: Count = 2
(IDictionary<string, object>) Request.Query.ToDictionary()
Count = 2
[0]: {[one, one]}
[1]: {[two, 2]}
Edit:
Based on your comment I assume you want to ALWAYS return JSON.
If that's the case the way you would do that is to return:
return Response.AsJson(dict);
This will serialize the dictionary as JSON for you.

Lua return index of a nested table

This is my first attempt to use Lua tables and I'm getting on with it quite well. I'm struggling with one thing though, heres (a small sample of) my table as it currently stands:
objects = {
["1/1/1"] = { tl = 1, startVal = 1, stopVal = 0 },
["1/1/2"] = { tl = 11, startVal = 1, stopVal = 0 },
["1/1/3"] = { tl = 22, startVal = 1, stopVal = 0 },
["1/1/4"] = { tl = 33, startVal = 1, stopVal = 0 },
}
The typical operation of this is that I use the "1/1/1" values as a lookup to the inner tables and then use those values in various functions. This all works well. Now, I need to go the other way, say I have tl = 22 coming in, I want to return the top value ("1/1/3" in this case).
I think I need to do something with the inpairs I keep seeing on the web but I'm struggling to implement. Any help would be massively appreciated.
You can't use ipairs because your table is an associated array not a sequence, so you have to use pairs. Also, there is no search function builtin to Lua, so you have to loop over all items yourself, looking for the right field value:
function findTL(tbl)
for key, data in pairs(tbl) do
if data.tl == tlSearch then
return key
end
end
end
local key = findTL(objects, 22)
If you want something a tad more object-oriented you could do this:
objects.findTL = findTL -- ok because first arg is the table to search
local key = objects:findTL(22)
isn't it better to take the value directly?
objects.1/1/1.tl
I don't know if it will work also with slashes, but if not, you may replace it by 'x' for example. Then it will be:
objects.1x1x1.tl

Resources