Search code examples
swiftnsdictionary

How to merge values with similar keys for NSdictionary


Hello i have situation where i have getting a raw response for the server like this

(
    {
        "Nov 2018" =         {
            AudioFileURL = "https://www.GeorgeA.m4a";
            AudioFileText = "GeorgeA";
        };
    },

    {
        "Nov 2018" =         {
            AudioFileURL = "https://www.GeorgeB.m4a";
            AudioFileText = "Georgeb";
        };
    },
    {
        "Nov 2018" =         {
            AudioFileURL = "https://www.Georgec.m4a";
            AudioFileText = "Georgec";
        };
    },
    {
        "Sep 2018" =         {
            AudioFileURL = "https://www.GeorgeB.m4a";
            AudioFileText = "GeorgeD";


        };
    }
)

now i would like to combine all the Values with the same key so that i can use them in section with UITableView controller . can someone please provide me some guidance for that .

The output i am looking for is something like this

(
{
        "Nov 2018" = {        
            [AudioFileURL = "https://www.GeorgeA.m4a";
            AudioFileText = "GeorgeA"],

            [AudioFileURL = "https://www.GeorgeB.m4a";
            AudioFileText = "GeorgeB"],

            [AudioFileURL = "https://www.GeorgeC.m4a";
            AudioFileText = "GeorgeC"];

        };
    },
{
        "Sep 2018" =         {
            [AudioFileURL = "https://www.GeorgeB.m4a";
            AudioFileText = "GeorgeD";]


        };
}
)

Solution

  • First make a struct(s) that represents the info you want in one cell:

    struct AudioFileInfo {
        let urlString: String
        let text: String
    
        init(dict: [String: String]) {
            urlString = dict["AudioFileURL"] ?? ""
            text = dict["AudioFileText"] ?? ""
        }
    }
    
    struct CellInfo {
        let date: String
        let audioFileInfos: [AudioFileInfo]
    }
    

    Then you can:

    let cellInfos = response
        .flatMap {
            $0.map { ($0.key, AudioFileInfo(dict: $0.value)) }
        }
        .reduce([CellInfo]()) { partial, item in
            var new = partial
            if let index = partial.index(where: { $0.date == item.0 }) {
                new[index] = CellInfo(date: partial[index].date, audioFileInfos: partial[index].audioFileInfos + [item.1])
            }
            else {
                new.append(CellInfo(date: item.0, audioFileInfos: [item.1]))
            }
            return new
        }
    

    This will give you an array of CellInfo objects.

    As a general rule, this how you solve this sort of problem. First define a type that represents the output you want, then manipulate the input until you create objects of that type. Playground is your friend for this sort of thing.