Array in Dictionary in Swift - arrays

My question is really simple and I guess it’s easy to do but, how to add an object into an array when the array is held in a dictionary in Swift language?
var dictionary = [String: [String]]()
for course in self.category.m_course_array
{
let firstChar = String(Array(course.getTitle())[0]).uppercaseString
dictionary[firstChar] = // How to add an element into the array of String
}

Not so easy as you might think, in fact. It's is a bit messy since you need to handle the fact that when the key isn’t present, you need to initialize the array. Here’s one way of doing it (code altered to be similar but stand-alone):
var dictionary = [String: [String]]()
let courses = ["Thing","Other Thing","Third Thing"]
for course in courses {
// note, using `first` with `if…let` avoids a crash in case
// you ever have an empty course title
if let firstChar = first(course).map({String($0).uppercaseString}) {
// get out the current values
let current = dictionary[firstChar]
// if there were none, replace nil with an empty array,
// then append the new entry and reassign
dictionary[firstChar] = (current ?? []) + [course]
}
}
Alternatively, if you want to use .append you could do this:
// even though .append returns no value i.e. Void, this will
// return Optional(Void), so can be checked for nil in case
// where there was no key present so no append took place
if dictionary[firstChar]?.append(course) == nil {
// in which case you can insert a single entry
dictionary[firstChar] = [course]
}

Try this
dictionary[firstChar].append(yourElement)
Since dictionary[firstChar] should get you your array

Related

How to filter duplicated elements until a new one comes

I want to filter out the duplicated elements until a new element comes using Swift. and I want to do this for the whole array.
Example: [1,1,1,2,2,1]
Output: [1,2,1]
You can use reduce(into:_:) to do so:
let array = [1,1,1,2,2,1]
let filtered = array.reduce(into: [Int]()) { partialResult, current in
guard let last = partialResult.last else { partialResult.append(current); return }
if last != current {
partialResult.append(current)
}
}
print(filtered)
We iterate over the array.
partialResult is the current new array being populated.
We check if there is already an initial value, else we add it.
Then, we compare last value of the partialResult with current value iterated of the initial array to decide if we append it or not to partialResult
Once you understood the logic, it could also be written with:
let filtered2 = array.reduce(into: [Int]()) { partialResult, current in
if partialResult.last != current {
partialResult.append(current)
}
}
print(filtered2)

How can I create an array that contains unique strings?

I want to create an array that contains unique strings. How can I do that?
var paths = make([]string, 0)
func main() {
// Members are added dynamically
paths = append(paths, "aaa")
paths = append(paths, "bbb")
paths = append(paths, "bbb")
paths = append(paths, "ccc")
// convert ["aaa", "bbb", "bbb", "ccc"] -> ["aaa", "bbb", "ccc"]
// or can I use some class that disallow the same string automaticaly?
}
If you want a collection of unique elements, that is the Set data type. Go does not have a builtin set data type, but you can use a map to act as a set: keys in a map must be unique.
For a "nice" set, use a map with bool value type (with true values) and exploit the zero value. For a set with the smallest memory footprint, use a map with struct{} value type as values of struct{} type occupy no memory; and use the comma-ok idiom to tell if a value is in the set / map.
Here's how the "nice" version of set looks like. Instead of a slice add your elements to a map[string]bool as the key with a true as the value:
m := make(map[string]bool)
m["aaa"] = true
m["bbb"] = true
m["bbb"] = true
m["ccc"] = true
To check if an element is already in the collection (map), you can simply use an index expression:
exists := m["somevalue"]
This exploits the zero value, that is if the map does not yet contain an element, the zero value of the value type is returned which is false in case of bool type, properly indicating that the element is not in the collection.
Elements in a map have no fixed order. If you need to keep the order (e.g. insertion order), then use a slice (to remember the order) and a map (to tell if an element to be added is new). This is easiest with a helper add() function:
var m = make(map[string]bool)
var a = []string{}
func main() {
add("aaa")
add("bbb")
add("bbb")
add("ccc")
}
func add(s string) {
if m[s] {
return // Already in the map
}
a = append(a, s)
m[s] = true
}

How can I replace a string in an array with a new string?

I am using a for loop to go through an array of strings. For each string, I am finding a new value for it. After finding the new value, I need to replace the string at the corresponding index.
var myStrings = [String]()
for var i = 0; i < myStrings.count; i++ {
let newValue: String = //Do some work to find the new value
myStrings[i] = newValue //This is what I thought would work, but I'm getting a crash and error saying that the array is out of index.
}
The error says that the array is out of index.
Figured it out. My work to find newValue involved the use of some closures. I had to redefine i as index inside a closure to be able to use it inside the closures.

Passing a string parameter to a func to access a property of an array

I am writing a data gathering and manipulation program in Swift (my first time trying to program in Swift).
I have a function (determineHeighestColumnValue) to which I pass two parameters; an array containing dictionary objects loaded from a core data persistent store and a string representing the key for property that I want to access from a dictionary object at a particular index in that array.
Each dictionary object looks similar to this:
{
debtorDays = "-";
debtors = "-";
eacFees = 284680;
eacToDateContribution = 117159;
eacToDateContributionPerFees = "41%";
eacToDateOtherCosts = 6985;
eacToDateReimburseable = 10640;
eacToDateSalary = 171176;
lastInvoice = NA;
lastRevisionDate = "11-Jun-15";
etc etc
I am trying to work out how I can pass the key as a string and then use that to access the associated array value through this piece of code - "pprFiles[index].item.toDouble()" in the if statement below. ".toDouble()" is a string extension that returns the double value of the string. The function is determining column heights so the values passed and being accessed in the dictionary object are all number values as Strings - hence the conversion to a Double.
When I run the code with the "item" parameter specifically typed as a key then the code works fine. However, as a passed parameter I get a compiler error on the if statement.
Any thoughts on how I can pass a string value and get the if statement to work would be gratefully received.
The function code is:
func determineHeighestColumnValue(pprFiles: Array<PPRRowData>, item: String) ->Array<Double>{
var tempArray: [Double] = []
let count = pprFiles.count
for var index = 0; index < count; index++ {
// ******* need to work out how to get the reference right in the next line for item to be index.item
if pprFiles[index].item.toDouble() != nil {
tempArray.append(item.toDouble()!)
} else {
tempArray.append(0)
}
}
let highestColumn = maxElement(tempArray.map({abs($0)}))
if highestColumn != 0 {
tempArray = tempArray.map({$0 / highestColumn})
} else {
tempArray = tempArray.map({$0 * 0})
}
return tempArray
}
You can use Key-Value Coding with Core Data managed objects:
if let val = pprFiles[index].valueForKey(item) as? String {
// ...
}

Swift Dictionary of Arrays

I am making an app that has different game modes, and each game mode has a few scores. I am trying to store all the scores in a dictionary of arrays, where the dictionary's key is a game's id (a String), and the associated array has the list of scores for that game mode. But when I try to initialize the arrays' values to random values, Swift breaks, giving me the error below. This chunk of code will break in a playground. What am I doing wrong?
let modes = ["mode1", "mode2", "mode3"]
var dict = Dictionary<String, [Int]>()
for mode in modes
{
dict[mode] = Array<Int>()
for j in 1...5
{
dict[mode]?.append(j)
let array:[Int] = dict[mode]!
let value:Int = array[j] //breaks here
}
}
ERROR:
Execution was interrupted, reason: EXC_BAD_INSTRUCTION(code=EXC_I386_INVOP, subcode=0x0).
Your problem is array subscripts are zero-based. So when you write:
var a: [Int] = []
for i in 1...5 {
a.append(42)
println(a[i])
}
you will get a runtime error, because first time around the loop you are subscripting a[1] when there is only an a[0]. In your code, you either need to do for j in 0..<5 or let value = array[j-1].
By the way, even though it’s perfectly safe to do dict[mode]! (since you just added it), it’s a habit best avoided as one of these days your code won’t be as correct as you think, and that ! will explode in your face. There’s almost always a better way to write what you want without needing !.
Also, generally speaking, whenever you use array subscripts you are risking an accidental screw-up by accidentally addressing an out-of-bounds index like here. There are lots of alternatives that mean actually using a[i] is easy to avoid:
If you want the indices for a collection (like an array), instead of:
for i in 0..<a.count { }
you can write
for i in indices(a) { }
If you want to number the elements in an array, instead of
for i in indices(a) { println("item \(i) is \(a[i])" }
you can write
for (i, elem) in enumerate(a) { println("item \(i) is \(elem)") }
If the collection happens to have an Int for an index (such as Array), you can use i as an index, but if it doesn’t (such as String) an alternative to get the index and element is:
let s = "hello"
for (idx, char) in Zip2(indices(s),s) { }
If you want the first or last element of an array, instead of:
if a.count > 0 { let x = a[0] }
if a.count > 0 { let x = a[a.count - 1] }
you can write
if let first = a.first { let x = first }
if let last = a.last { let x = first }
Prefer map, filter and reduce to for loops in general (but don’t obsess over it, sometimes a for loop is better)

Resources