nwales
nwales

Reputation: 3561

Swift - issue with initializing and appending to arrays in dictionary

Here's what I am trying to do:

I am starting with an array of ArticleItem objects. Those objects have a property on them named 'category' which is a string. I'm trying to loop through all of my ArticleItem objects and group items with like categories in a dictionary. I'm using the category name as my key. The issue I am having is that my dictionary keys are hold arrays that never contain more than 1 object. I definitely have more than 3 objects with the same category name. Here is the relevant code from my class. I'd love to understand the right way to do this..

private var _articlesDict:[String:[ArticleItem]]

init(articles:[ArticleItem]) {
    _articlesDict = [String:[ArticleItem]]()

    for item:ArticleItem in articles {
        var optionalCatArray:[ArticleItem]? = _articlesDict[item.category]
        if let catArray = optionalCatArray {
            optionalCatArray!.append(item) //why can't I do catArray.append(item)?
        } else {
            var arr:[ArticleItem] = [ArticleItem]()
            arr.append(item)
            _articlesDict[item.category] = arr
        }
    }
}

Upvotes: 0

Views: 1776

Answers (3)

rob mayoff
rob mayoff

Reputation: 385870

As an alternative to the native-array solutions in other answers, you could do this:

var _articlesDict = [String:NSMutableArray]()

init(articles:[ArticleItem]) {
    for item:ArticleItem in articles {
        if let array = _articlesDict[item.category] {
            array.addObject(item)
        } else {
            _articlesDict[item.category] = NSMutableArray(object:item)
        }
    }
}

But keep in mind you'll have to cast to ArticleItem when you extract items from the arrays in the dictionary.

Upvotes: 0

Antonio
Antonio

Reputation: 72760

The problem is that arrays are value types, so they are passed by value and not by reference. That means that every time you assign a variable holding an array to another variable (or array, or dictionary) you actually create a copy of it. But there's more.

1st problem

This line of code:

if let catArray = optionalCatArray {

creates an immutable copy of optionalCatArray, so it cannot be modified. Use this instead:

if optionalCatArray != nil {

2nd problem

This line of code:

var optionalCatArray:[ArticleItem]? = _articlesDict[item.category]

creates a copy of the array stored in the dictionary - here:

if optionalCatArray != nil {
    optionalCatArray!.append(item)

assign a new item to the array, but remember: this is a copy, so you are not modifying the array contained in the dictionary. What's missing is setting it back into the dictionary:

if optionalCatArray != nil {
    optionalCatArray!.append(item)
    _articlesDict[item.category] = optionalCatArray!
}

Probably this code can be improved by avoiding the array copy like this:

if _articlesDict[item.category]  != nil {
    _articlesDict[item.category]!.append(item)
} else {
    _articlesDict[item.category] = [item]
}

I haven't tested it, but conceptually it should work. Also note how I shortened the else branch, easier to read.

Upvotes: 1

fluidsonic
fluidsonic

Reputation: 4676

You cannot edit an array in a dictionary directly. You append to a local copy only.

See https://stackoverflow.com/a/24251066/1183577 for more info.

Upvotes: 0

Related Questions