When I see a field:value pair as
"name":"foo" and "name":foo
what is the difference between the two? Are both the values supposed to be strings?
And what about
"age":3 and "age":"3"
Is the first one an integer? I am confused.
Thanks.
Strings vs. variables
The following assigns the string value "foo" to a property:
item = { "name" : "foo" } // item.name = "foo"
The following assigns the value of the foo variable to a property. If the foo variable doesn't exist, you'll receive an error message:
item = { "name" : foo } // foo doesn't exist yet, will result in error
foo = "my value" // foo is defined here
item = { "name" : foo } // item.name = "my value"
Numbers vs. strings
The following assigns a Number value to a property:
child = { "age" : 3 } // child.age = 3
Numbers can be used in all mathematical operations. For example, child.age * 3 will result in 9 and child.age + 4 will result in 7.
The following assigns a string value to a property:
child = { "age" : "3" } // child.age = "3"
Strings cannot be used in all calculations. For example, child.age * 3 will result in 9, but child.age + 4 will result in 34, due to string concatenation.
You should only use strings if the data is textual data. If the data is numerical, store it as a number (without the quotes).
Related
I have varying input that will be a String like:
"James"
"James(1)"
"James(2)"
I'm looking to insert the values for these keys into a dictionary only after I remove the (x)
What can I use to represent x to then remove the entire parenthesis?
My current attempt looks like this:
replacingOccurrences(of: "(\((Any).self)", with: "")
But that's not working..
Desired output would be a dictionary only containing the one unique value as the key.
So with the input of
["James" : 3, "James(1)" : 3, "James(2)" : 4, "Sarah" : 10, "Sarah(1)" : 10, "Sarah(2)" : 10 ]
I would get this output
["James" : 10, "Sarah" : 30]
I like George's solution, but I think this is a nice use case for uniquingKeysWith:.
// Convert to [(name, value)], removing everything after "("
let keyValues = data.map { k, v in (String(k.prefix(while: { $0 != "(" })), v) }
// Sum matching values
let result = Dictionary(keyValues, uniquingKeysWith: +)
Easiest way would be to use reduce(into:_:).
It works by:
Starting with an empty dictionary to create in the reduce.
Get index of first bracket/parenthesis (nil if none)
Get the name excluding anything after the (. Otherwise take whole name.
Append the value from the input for the current key as the name. If the name doesn't exist yet, default value of 0 is given.
Code:
let input = ["James": 3, "James(1)": 3, "James(2)": 4, "Sarah": 10, "Sarah(1)": 10, "Sarah(2)": 10]
let output: [String: Int] = input.reduce(into: [:]) { partialResult, pair in
let firstBracket = pair.key.firstIndex(of: "(")
let basicName = String(pair.key.prefix(upTo: firstBracket ?? pair.key.endIndex))
partialResult[basicName, default: 0] += pair.value
}
print(output)
// Prints: ["James": 10, "Sarah": 30]
I need to create an array with these info:
Fruits: Counts("apple":"14","orange":"3","grape":"6", ...)
And then search in it to see if we have any (fruit) indexed? and if not add it with 1 quantity, and if it exist, add 1 to its (counts)
Here you go -
var fruits:[String:Int] = ["apple":14,"orange":3,"grape":6]
let filtered = fruits.filter({$0.key.elementsEqual("apple")})
fruits["apple"] = (fruits["apple"] ?? 0) + 1
print(fruits["apple"])
At very first line you create a dictionary of your key and values.
in second line you filter the dictionary with the desired key which is in this case apple you can even make this key as variable and replace the apple with variable. In return of filter you get an array of filtered values with provided key. Now you simply check if the count of this is greater then 0, which means there exist a value for provided key. If it is there you increment it by one else you create a new value with the key.
var fruitCount : [String : Int] = ["apple" : 14, "orange" : 3, "grape" : 6];
func addFruit( FruitName name : String ) {
for (fruitName , count) in fruitCount {
if ( fruitName == name ) {
fruitCount[name]! += 1 // fruitCount[name] return optional(Int) so, unwrap force!
return
}
}
fruitCount[name] = 1
}
addFruit(FruitName: "apple")
addFruit(FruitName: "kiwi")
print(fruitCount)
We can see
["orange": 3, "apple": 15, "grape": 6, "kiwi": 1]
This question already has an answer here:
Swift, get variable name from a string
(1 answer)
Closed 6 years ago.
Sequential variable names defined. I want to reach a variable relative to the corresponding value.
var code = 2 // 5, 6, ... // corresponding values
var name : String
var name1 : String = "Aaaaaa"
var name2 : String = "Bbbbbb"
// var name3
// var name4 ...
name = "name" + String(code) // name = "Bbbbb" ??
I do not get the results I wanted.
I hope i explained correctly. Thank you for your help.
Unlike in Objective-C, you can't access a variable by a String of its name in Swift. In your case, you might want to just use an array:
var code = 2 // 5, 6, ... // corresponding values
var names = ["Aaaaaa", "Bbbbbb"]
var name = names[code - 1] // "Bbbbbb"
If you really want to do it dynamically from a string name, you'll have to bridge to Objective-C, for example:
class SomeObject: NSObject {
var name1 : String = "Aaaaaa"
var name2 : String = "Bbbbbb"
func getName(code: Int) -> String {
let name = valueForKey("name" + String(code)) as! String // "Bbbbbb"
return name
}
}
SomeObject().getName(2) // "Bbbbbb"
Of course, by doing this, you lose a lot of the safety that Swift provides.
Note: My issue #4417 was closed, but I didn't want to be that guy who opens another issue for the same thing.
Based on #3132, [ { "a": 1, "b": 2 }, { "a": 2 } ] doesn't compile unless you specifically type it to Array<Dynamic> or whatever type encompasses both. That's fine I guess, but inside of the build macro below, there is nowhere for me to type the array, and I get an error.
In general, I can make map literal notation work using untyped (http://try.haxe.org/#3dBf5), but I can't do that here since my types haven't been constructed yet.
macro public static function test():Array<Field> {
var fields = Context.getBuildFields();
// parse the JSON
var o = Context.parseInlineString('{ "arr": [ { "a": 1, "b": 2 }, { "a": 2 } ] }', Context.currentPos());
// ["test" => json] map literal notation
var a = [{ expr : EBinop(OpArrow, macro $v { "test" }, o), pos : Context.currentPos() }];
// creates: "public var json:StringMap<Dynamic> = ['test' => json];"
var nf:Field = {
name : "json",
doc : "docs",
meta : [],
access : [APublic],
kind : FVar(macro : haxe.ds.StringMap<Dynamic>, { expr : EArrayDecl(a), pos : Context.currentPos() } ),
pos : Context.currentPos()
};
fields.push(nf);
return fields;
// error: Arrays of mixed types...
}
Without knowing ahead of time what the structure of the json is, is there anything I can do?
You can still use untyped, by constructing an intermediate EUntyped(o) expression (more simply macro untyped $o).
Alternatively, you can traverse the parsed object and add ECheckType to Dynamic expressions to every array, generating something like to ([...]:Array<Dynamic>).
The implementation of this would look something like calling the following checkTypeArrays function with your parsed o object, before building the map literal expression.
static function checkTypeArrays(e:Expr):Expr
{
return switch (e) {
case { expr : EArrayDecl(vs), pos : pos }:
macro ($a{vs.map(checkTypeArrays)}:Array<Dynamic>);
case _:
haxe.macro.ExprTools.map(e, checkTypeArrays);
}
}
An improvement to this would be to only wrap in (:Array<Dynamic>) the arrays that fail Context.typeof(expr).
This question already has answers here:
Swift dictionary get key for value
(11 answers)
Closed 7 years ago.
My code looks like this:
var dict = ["a": 1, "b": 2]
var valueInDict = 1
My question is whether it's possible to access the key, in this case "a", using only the value.
Use the fact that Dictionary values and keys properties are documented to have the same order:
if let index = dict.values.indexOf(valueInDict) {
let key = dict.keys[index]
print(key)
}
It is not possible to get the key by its value, because multiple keys can have the same value. For example, if you make a dictionary like this
let dict = [
"a" : 7
, "b" : 3
, "c" : 11
, "d" : 7
, "e" : 3
, "f" : 11
]
and try to find the key of value 7, there would be two such keys - "a" and "d".
If you would like to find all keys that map to a specific value, you can iterate the dictionary like this:
let search = 7
let keys = dict // This is a [String:int] dictionary
.filter { (k, v) -> Bool in v == search }
.map { (k, v) -> String in k }
This produces keys of all entries that have the search value, or an empty array when the search value is not present in the dictionary.