Storing Dictionaries in Array ArrayLiterialConversion Error - arrays

I am trying to create a array to hold dictionaries.
var deaultScoreResults : [Dictionary<String, Int>] = [];
But when I try to add a dictionary key:value pair I get:
deaultScoreResults.append(["Study Up!", 1]);
Error;
Type 'Dictionary' does not conform to protocol
'ArrayLiteralConvertible'

Square brackets surrounding a comma separated list of values is an array literal.
["this", "is", "a", "swift", "literal", "array"]
For a literal dictionary, you need a comma separated list of key:value pairs:
[1:"this", 2:"is", 3:"a", 4:"swift", 5:"literal", 6:"dictionary"]
To fix the error, you simply need to change your comma to a colon:
defaultScoreResults.append(["Study Up!":1])
However, based on your previous question, I'm going to assume an array of <String, Int> dictionaries isn't anywhere near what you're looking for.
I would suggest that you want simply an <Int, String> dictionary:
var defaultScoreResults = Dictionary<Int, String>()
defaultScoreResults[1] = "Study Up!"

Try this:
var deaultScoreResults = [Dictionary<String, Int>]()
deaultScoreResults.append(["Study Up!":1])
You could also declare it like this:
var deaultScoreResults = [[String:Int]]()

Related

How prevent Object.keys() sort?

The problem with the ECMA standard for sort of Object.keys() is known:
Object.keys() handle all keys with integer (example: 168), including integer as strings (example: "168"), as a integer. The result is, both are the same (168 === "168"), and overwrite itself.
var object = {};
object["168"] = 'x';
object[168] = 'y';
Object.keys(object); // Array [ "168" ]
object[Object.keys(object)]; // "y"
Interestingly, all keys (including pure integer keys) are returned as a string.
The ecma262 wrote about this: All keys will be handle as a integer, expect the key is a String but is not an array index.
https://tc39.es/ecma262/#sec-ordinaryownpropertykeys
That should tell us: 168 === "168". A toString() do not solve the problem.
var object = {};
object[[3].toString()] = 'z';
object[[1].toString()] = 'x';
object[[2].toString()] = 'y';
Object.keys(object);
// Array(3) [ "1", "2", "3" ]
Paradoxically, in this case, only integer apply as "enumerable" (it's ignoring array.sort(), that sort also strings with letters.).
My question about this is simple: How can i prevent the sort function in Object.keys()? I have testet the Object.defineProperties(object, 1, {value: "a", enumerable: true/false}), but that mean not realy enumerable in the case of integer or string or integer-like string. It means only should it be counted with or not. It means "counted" like omit (if it false), not "enumerabled" like ascending or descending.
A answere like that is not a good answer: Please use only letters [a-zA-Z] or leastwise a letter at the first position of keyword.
What I want: That the keys are not sorted, but output in the order in which they were entered, whether integer, string or symbol.
Disclaimer: Please solutions only in JavaScript.
Javascript Objects are unordered by their nature. If you need an ordered object-like variable I would suggest using a map.
To achieve what you're looking for with a map instead of object you'd do something like the below:
var map1 = new Map();
map1.set("123", "c");
map1.set(123, "b");
var iterator1 = map1.keys();
var myarray = [];
for (var i = 0; i < map1.size; i++) {
myarray.push(iterator1.next().value);
}
console.log(myarray);
// Array ["123", 123]
Unfortunately it's not compatible with IE and I'm not sure how else you could achieve what you need without it. A quick Google did return something about jQuery maps, though.
If you don't want to use jQuery and still need to support IE some points are below:
Is there anything stopping you using an array rather than JS object to store the data you need? This will retain the order per your requirements unlike objects. You could have an object entry in each iteration which represents the key then use a traditional foreach to obtain them as an array. I.e.
The array:
var test_array = [
{key: 123, value: 'a value here'},
{key: "123", value: 'another value here'}
];
// console.log(test_array);
Getting the keys:
var test_array_keys = [];
test_array.forEach(function(obj) { test_array_keys.push(obj['key']); } );
// console.log(test_array_keys);
Then if you needed to check whether the key exists before adding a new entry (to prevent duplicates) you could do:
function key_exists(key, array)
{
return array.indexOf(key) !== -1;
}
if(key_exists('12345', test_array_keys))
{
// won't get here, this is just for example
console.log('Key 12345 exists in array');
}
else if(key_exists('123', test_array_keys))
{
console.log('Key 123 exists in array');
}
Would that work? If not then the only other suggestion would be keeping a separate array alongside the object which tracks the keys and is updated when an entry is added or removed to/from the object.
Object Keys sorted and store in array
First Creating student Object. then sort by key in object,last keys to store in array
const student={tamil:100, english:55, sci:85,soc:57}
const sortobj =Object.fromEntries(Object.entries(student).sort())
console.log(Object.keys(sortobj))
use map instead of an object.
let map = new Map()
map.set("a", 5)
map.set("d", 6)
map.set("b", 12)
to sort the keys (for example, to update a chart data)
let newMap = new Map([...map.entries()].sort())
let keys = Array.from(newMap.keys()) // ['a','b','d']
let values = Array.from(newMap.values()) // [5,12,6]

How to check a value is inside nested dictionary swift

I have a problem concerning my nested dictionary.
var level1Dictionary = [String : [String : String]]()
var ChosenDeckLabel = [String]
textview.text
I want to see if the dictionary contains a certain value within my, else if statement as such:
else if level1Dictionary[ChosenDeckLabel[textview.text]] != nil {
this returns error:
Cannot subscript value of type String with an index of type String!
How should I cast it to check if the nested dictionary contains the value?
Dictionaries are optionals by default because they are not sure if a key/value pair exist. Be sure to include your "!" AND "?" to wrap and unwrap your data being passed.
Arrays offer subscripting via integers and ranges as seen in Swift's API:
public subscript (index: Int) -> Element
public subscript (subRange: Range<Int>) -> ArraySlice<Element>
You're trying to subscript via a string which is throwing the error. You need to get the index of the element in the array and then use that to subscript the array to get the value: e.g.
let dictOfDicts = [String : [String : String]]()
var arrayOfStrings: [String] = ["a", "b", "c"]
let stringToCheck = "a"
dictOfDicts["a"] = ["some": "thing"]
if let index = array.indexOf(stringToCheck) {
if dictOfDicts[array[Int(index)]] != nil {
// do something
}
}
I think this is what you intend to do:
else if level1Dictionary[strIndex1][strIndex2] != nil {
When you are doing this:
level1Dictionary[ChosenDeckLabel[textview.text]]
you are trying to access the ChosenDeckLabel array using a String subscript:
ChosenDeckLabel[textview.text]
which is not a valid operation. Arrays are Int indexed and not string indexed.

Swift: Accessing array value in array of dictionaries

I am currently struggling with obtaining a value from an array inside an array of dictionaries. Basically I want to grab the first "[0]" from an array stored inside an array of dictionaries. This is basically what I have:
var array = [[String:Any]]()
var hobbies:[String] = []
var dict = [String:Any]()
viewDidLoad Code:
dict["Name"] = "Andreas"
hobbies.append("Football", "Programming")
dict["Hobbies"] = hobbies
array.append(dict)
/// - However, I can only display the name, with the following code:
var name = array[0]["Name"] as! String
But I want to be able to display the first value in the array stored with the name, as well. How is this possible?
And yes; I know there's other options for this approach, but these values are coming from Firebase (child paths) - but I just need to find a way to display the array inside the array of dictionaries.
Thanks in advance.
If you know "Hobbies" is a valid key and its dictionary value is an array of String, then you can directly access the first item in that array with:
let hobby = (array[0]["Hobbies"] as! [String])[0]
but this will crash if "Hobbies" isn't a valid key or if the value isn't [String].
A safer way to access the array would be:
if let hobbies = array[0]["Hobbies"] as? [String] {
print(hobbies[0])
}
If you use a model class/struct things get easier
Given this model struct
struct Person {
let name: String
var hobbies: [String]
}
And this dictionary
var persons = [String:Person]()
This is how you put a person into the dictionary
let andreas = Person(name: "Andreas", hobbies: ["Football", "Programming"])
persons[andreas.name] = Andreas
And this is how you do retrieve it
let aPerson = persons["Andreas"]

Convert array in quotation marks to just an array

I currently have a string, that's supposed to be an Array:
var content = "['A','B','C']"
//What I want -> var content = ['A', 'B', 'C']
I need to remove the quotation marks, so that it's just an Array, i.e. String to Array. How would one attempt that?
This looks similar to JSON syntax except that the single quotes should be double quotes.
Well then, let's just do that:
let source = "['A','B','C']"
Replace single quotes with double quotes:
let content = source.stringByReplacingOccurrencesOfString("'", withString: "\"")
Then convert the String to NSData (becomes valid JSON):
guard let data = content.dataUsingEncoding(NSUTF8StringEncoding) else { fatalError() }
Finally, convert the JSON data back to a Swift array of Strings:
guard let arrayOfStrings = try NSJSONSerialization.JSONObjectWithData(data, options: []) as? [String] else { fatalError() }
Result:
print(arrayOfStrings)
["A", "B", "C"]
print(arrayOfStrings[1])
"B"
Here's a semi-hacky solution to your specific example.
let content = "['A','B','C']"
var characters = content.characters
characters.removeFirst(2) // Remove ['
characters.removeLast(2) // Remove ']
let contentArray = String(characters).componentsSeparatedByString("','")
print(contentArray) // ["A", "B", "C"]
Disclaimer/Warning:
This solution isn't robust as it expects your array to only contain objects wrapped in ' characters. It will however work for any length of string (e.g. replacing A with foo will work).
If your actual content string is any more complex than what you have here then I would take Rob's advice and try JSON serialization (especially if this string comes from a place you don't control like the server).
You could do this one:
let arr = content.componentsSeparatedByCharactersInSet(NSCharacterSet (charactersInString: "['],")).filter({!$0.isEmpty})
Explanation:
First, we split the string into an array based upon separators like: [, ', ,, ]
We now have an array with some empty strings, we use filter() to remove them.
And Voila !
Warning:
like #nebs' warning, carefull with this solution. If your string is composed by more complexe strings (ex: "['Hello [buddy]', 'What's up?', 'This is a long text, or not?']"), especially string composed with the separators, you will get an array that will not match with your expected result.

Generating a JSON-Array and converting it to a Base64-String

I'm trying to create a Base64-String in Swift. I have an example of a Base64-encoded string and its array-counterpart. My problem now is, that I don't know how I get an equivalent array to the one which is given in the example.
Because I didn't want to mess around in my XCode-project I did the following in a playground.
given array:
{"WHERE":{"Class":"%3f","Location":"3b"},"ORDER":["Day ASC","Location DESC"]}
given Base64-string:
eyJXSEVSRSI6eyJDbGFzcyI6IiUzZiIsIkxvY2F0aW9uIjoiM2IifSwiT1JERVIiOlsiRGF5IEFTQyIsIkxvY2F0aW9uIERFU0MiXX0=
First I'm decoding the example-string
let str = "eyJXSEVSRSI6eyJDbGFzcyI6IiUzZiIsIkxvY2F0aW9uIjoiM2IifSwiT1JERVIiOlsiRGF5IEFTQyIsIkxvY2F0aW9uIERFU0MiXX0="
let data = NSData(base64EncodedString: str, options: NSDataBase64DecodingOptions(rawValue: 0))
do {
let result = try NSJSONSerialization.JSONObjectWithData(data!, options: .AllowFragments)
} catch let error {
print(error)
}
//"result" is ["WHERE": ["Class": "%3f", "Location": "3b"], "ORDER": ["Day ASC", "Location DESC"]]
Below I'm trying to reproduce the string from above
var array = [String : AnyObject]()
var arrayPartA = [String : String]()
arrayPartA["Class"] = "%3f"
arrayPartA["Location"] = "3b"
array["ORDER"] = ["Day ASC", "Location DESC"]
array["WHERE"] = arrayPartA
array //The playground says that "array" is ["ORDER": ["Day ASC", "Location DESC"], "WHERE": ["Class": "%3f", "Location": "3b"]]
//"ORDER" and "WHERE" are switched but I don't get them to be at the right position
let utf8str2: NSData = String(array).dataUsingEncoding(NSUTF8StringEncoding)!
let encodedStr = utf8str2.base64EncodedStringWithOptions(NSDataBase64EncodingOptions(rawValue: 0))
//Here "encodedStr" is WyJPUkRFUiI6ICgKICAgICJEYXkgQVNDIiwKICAgICJMb2NhdGlvbiBERVNDIgopLCAiV0hFUkUiOiB7CiAgICBDbGFzcyA9ICIlM2YiOwogICAgTG9jYXRpb24gPSAzYjsKfV0=
//but it should be eyJXSEVSRSI6eyJDbGFzcyI6IiUzZiIsIkxvY2F0aW9uIjoiM2IifSwiT1JERVIiOlsiRGF5IEFTQyIsIkxvY2F0aW9uIERFU0MiXX0=
I would be glad if someone could explain to me what I'm doing wrong and how I can reproduce the given Base64-string.
Since I'm new to this website I apologize in advance for wrong layout or other possible conventions I don't know.
Could you try this please? Is this what you wanted to do? It should convert a Dictionary to base64 String
func jsonToBaseString (yourJSON: [String: String]) -> String? {
do {
let jsonData = try JSONSerialization.data(withJSONObject: yourJSON, options: JSONSerialization.WritingOptions.prettyPrinted)
return
jsonData.base64EncodedString(options: .endLineWithCarriageReturn)
} catch {
return nil
}
}
Dictionary is Swifts JSON representation...
Two important things to understand:
What you are calling an array is not an array, it's a JSON dictionary (containing an array for the ORDER key).
Be careful not to confuse the syntax of arrays and dictionaries between Swift and JSON.
In Swift, an array: [0, 1], a dictionary: ["a":0, "b":1].
In JSON, an array: [0, 1], a dictionary: {"a":0, "b":1}.
A Swift dictionary is an unordered collection. There's no "position" for key-value pairs.
You'll need to change several things:
Your input string (not serialized) is not an array, but a JSON object.
Try constructing your string with a proper JSON library, such as SwiftyJSON.
String(array) is not enough to consistently convert your objects to strings. You should use a JSON serializer (such as SwiftyJSON json.rawString()).
let follow recommendation to use some json serialization, but take in account that
{
"alfa": 1,
"beta": true
}
and
{"beta":true,"alfa":1}
represents in JSON notation the same object even though their string representation ( doesn't matter if base64 encoded or not ) are different.

Resources