Home > front end >  Optionals in Dictionary Arrays
Optionals in Dictionary Arrays

Time:03-22

I am working on some code and have received incorrect output and have been attempting to resolve it, I know its a pretty straightforward fix (or at least is should be) possibly casting it correctly or handling it. However, I have had a number of attempts with no success.

Here is the code in a Swift Playground

import UIKit
import Foundation

//  MARK:- Declarations

//  The varible defintions including the expected unique key values, the associated data and the dictionary which will be returned
var arrayOfUniqueFieldNames = ["value1", "value2", "value3"]
var dictionaryOfKeyPairedData : [Int: [String]] = [
    0: ["value1", "a"],
    1: ["value2", "b"],
    2: ["value3", "c"],
    3: ["value1", "x"],
    4: ["value2", "y"],
    5: ["value3", "z"]]
var dictionaryOfDatasets = [String: Any]()

// MARK:- Code Body

//  Iterates through the dictionaryOfKeyPairedData assigning each key if it doesn't exist to the array to print and the value to the existing key, each key has mutliple values stored as an array
for counterOne in 0...dictionaryOfKeyPairedData.count-1{
    
    //  gets the current key value from the dictionary as a String
    let currentKeyValue = returnKeyofDictionaryArray(theDictionaryInQuestion: dictionaryOfKeyPairedData, indexToLookUp: counterOne, value: 0)
    //  gets the current value from the dictionary as a String as it associates with the current key
    let currentValuePair = returnKeyofDictionaryArray(theDictionaryInQuestion: dictionaryOfKeyPairedData, indexToLookUp: counterOne, value: 1)
    //  Fetches the array from the dictionary so it can be manipulated
    var existingItems = Array(arrayLiteral: dictionaryOfDatasets[currentKeyValue]) //Where I believe the Optional is not handled correctly
    //  If the key doesn't exist it saves the value as the key to the key, if it does exist it saves the value to the value as a value
    if existingItems[0] == nil{
        existingItems = [currentValuePair] //Where I believe the extranious brackets are getting added
    }else{
        existingItems.append(currentValuePair)
    }
    //  resaves the manipulated array alongside the existing key
    dictionaryOfDatasets[currentKeyValue] = existingItems
}

//  prints the data - OUTPUT
print(dictionaryOfDatasets)


//  MARK:- Functions
//  Returns the key for the value for the prescribed array
func returnKeyofDictionaryArray(theDictionaryInQuestion: [Int: [String]], indexToLookUp: Int, value: Int) -> String{
    return theDictionaryInQuestion[indexToLookUp]![value]
}

The expected output is

["value2": ["b", "y"], "value1": ["a", "x"], "value3": ["c","z"]]

or

["value1": ["a", "x"], "value2": ["b", "y"], "value3": ["c","z"]]

The Actual output is

["value1": [Optional([Optional("a")]), Optional("x")], "value2": [Optional([Optional("b")]), Optional("y")], "value3": [Optional([Optional("c")]), Optional("z")]]

CodePudding user response:

You are using Any as the type for the value of your output dictionary, while it can just be an array of Strings. And using Array(arrayLiteral: dictionaryOfDatasets[currentKeyValue]) does not help.

You can obtain the result you want by iterating through the original dictionary and storing the values directly into the new one, with no supporting function like returnKeyofDictionaryArray.

Here is how you can achieve this:

        //  The variable defintions including the expected unique key values, the associated data and the dictionary which will be returned
        var arrayOfUniqueFieldNames = ["value1", "value2", "value3"]
        var dictionaryOfKeyPairedData : [Int: [String]] = [
            0: ["value1", "a"],
            1: ["value2", "b"],
            2: ["value3", "c"],
            3: ["value1", "x"],
            4: ["value2", "y"],
            5: ["value3", "z"]]
        
        // This is a dictionary of String to String-arrays
        var dictionaryOfDatasets = [String: [String]]()

        // MARK:- Code Body
        
        // Just iterate through the values of the dictionary, given that
        // you are not interested in the Int keys
        dictionaryOfKeyPairedData.values.forEach {
            if dictionaryOfDatasets[$0[0]] == nil {
                dictionaryOfDatasets[$0[0]] = [$0[1]]
            } else {
                dictionaryOfDatasets[$0[0]]?.append($0[1])
            }
        }
        
        // Sorting, if you need:
        // Here is where you sort the arrays inside each value of the dictionary
        dictionaryOfDatasets.keys.forEach {
            dictionaryOfDatasets[$0] = dictionaryOfDatasets[$0]?.sorted(by: { $0 < $1 })
        }

        //  prints the data - OUTPUT
        print(dictionaryOfDatasets)   // ["value3": ["c", "z"], "value2": ["b", "y"], "value1": ["a", "x"]]

CodePudding user response:

You , first you need to change Dictioanry key Any with String And you can achieve the expected result with more elegant way

var arrayOfUniqueFieldNames = ["value1", "value2", "value3"]
var dictionaryOfKeyPairedData : [Int: [String]] = [
    0: ["value1", "a"],
    1: ["value2", "b"],
    2: ["value3", "c"],
    3: ["value1", "x"],
    4: ["value2", "y"],
    5: ["value3", "z"]]
var dictionaryOfDatasets = [String: [String]]()

arrayOfUniqueFieldNames.forEach{
    let key = $0
    dictionaryOfKeyPairedData.filter({$0.value.first == key}).forEach{
        if dictionaryOfDatasets[key] != nil {
            var val = dictionaryOfDatasets[key]
            val?.append($0.value.last ?? "")
            dictionaryOfDatasets[key] = val

        }else{
            dictionaryOfDatasets[key] = [$0.value.last ?? ""]

        }
    }
}
print(dictionaryOfDatasets)

OUTPUT:

["value1": ["a", "x"], "value3": ["z", "c"], "value2": ["y", "b"]]
  • Related