Generate Sorted Dictionary by Letters from an Array Swift - ios

I have an Array of Departments' Names
var departments: Array<String>!
I want to sort this array alphabetically in Dictionary e.g the dictionary should be like this
var MyDictionary = ["A": ["Affenpoo", "Affenpug", "Affenshire", "Affenwich", "Afghan Collie", "Afghan Hound"], "B": ["Bagle Hound", "Boxer"],
"C": ["Cagle Cound", "Coxer"]]
the departments array is not static
how can i generate this dictionary in swift?
Thanks a lot

My approach would be to iterate the array and take the first letter of each entry. Retrieve the array from the dictionary for that letter. If it is nil create a new array. Add the word to the array you retrieved and then store the array in the dictionary.
let departments = ["Affenpoo", "Affenpug", "Affenshire", "Affenwich", "Afghan Collie","Cagle Cound", "Coxer"]
var outputDict=[String:[String]]()
for word in departments {
let initialLetter=word.substringToIndex(word.startIndex.advancedBy(1)).uppercaseString
var letterArray=outputDict[initialLetter] ?? [String]()
letterArray.append(word)
outputDict[initialLetter]=letterArray
}
print(outputDict)
["C": ["Cagle Cound", "Coxer"], "A": ["Affenpoo", "Affenpug", "Affenshire", "Affenwich", "Afghan Collie"]]

EDIT: solution by Paulw11 is more efficient
I don't think this question is relevant to swift in particular, but anyways try this:
let a = ["All", "Cat", "red", "gat", "Star sun", "bet you", "Zeta Fog", "Tea", "Fox"]
let b = a.map{ $0.lowercaseString }
let c = b.sort()
let d = c.map{ $0[$0.startIndex.advancedBy(0)]}
var dictionary:[String:[String]] = [:]
let byInitial = d.map{ initial in
let clustered = c.filter{$0.hasPrefix("\(initial)")}
dictionary.updateValue(clustered, forKey:"\(initial)")
}
print("\(dictionary)")

Related

iterating through dictionary in TableView

this might be a common situation, but I was not able to figure out a way how to do it.
I have a dictionary with the stock amount for several items: dict = ["item1" : 2, "item2" : 5, "item3" : 10 ]
How can I now assign the keys and values to different labels in a tableView, using indexPath?
The logic I want to achieve:
cell.itemLabel.text = dict.[firstItemName]
cell.amountLabel.text = dict.[firstItemAmount]
A dictionary as data source can be annoying because a dictionary is unordered.
My suggestion is to map the dictionary to an array of a custom struct and sort the array by the keys
struct Model {
let name : String
let value: Int
}
let dict = ["item1" : 2, "item2" : 5, "item3" : 10 ]
let array = dict.map(Model.init).sorted{$0.name < $1.name}
Then in the table view you can write
cell.itemLabel.text = array[indexPath.row].name
You can use map function to get separate array of key and values
print(dict.map({$0.key}))
print(dict.map({$0. value}))
Try this:
cell.itemLabel.text = dict.map({$0.key})[indexPath.row]
cell.amountLabel.text = dict.map({$0.value})[indexPath.row]

How to get all "title" values from dictionary of array in swift 5

Swift 5
I want to get array of all values from "title" key
// Create variable
var arrSportsList:[[String:String]] = []
// viewDidLoad code
arrSportsList = [
["title":"Cricket"],
["title":"Soccer"],
["title":"American Football"],
["title":"Ice Hockey"],
["title":"Tennis"],
["title":"Baseball"],
["title":"Basketball"],
]
I want to use this title in picker view.
You can use compactMap:
let titleArr = arrSportsList.compactMap { $0["title"] }
It transforms each dictionary to the value associated with the key title, and removes the dictionaries which don't have a title key.
I also suggest you to create a class/struct to store these sports, instead of dictionaries:
struct Sport {
let title: String
// other properties
}
Use compactMap(_:) method to get the title value from all dictionaries. If any dictionary doesn't contain title key it will be ignored
var arrSportsList:[[String:String]] = []
// viewDidLoad code
arrSportsList = [
["title1":"anothergame"],
["title":"Cricket"],
["title":"Soccer"],
["title":"American Football"],
["title":"Ice Hockey"],
["title":"Tennis"],
["title":"Baseball"],
["title":"Basketball"],
]
let titleArr = arrSportsList.compactMap { $0["title"] }
print(titleArr)//Cricket,Soccer,American Football,Ice Hockey,Tennis,Baseball,Basketball
Easiest way
let titleArr = arrSportsList.compactMap { $0["title"] }
Or you can loop through the dictionary array and can get the titles Like
let titleArr = Array<String>();
for dict in arrSportsList {
if let title = dict["title"] {
titleArr.append(title);
}
}
In case of understanding more, you can use
// Create variable
var arrSportsList:[[String:String]] = []
// viewDidLoad code
arrSportsList = [
["title":"Cricket"],
["title":"Soccer"],
["title":"American Football"],
["title":"Ice Hockey"],
["title":"Tennis"],
["title":"Baseball"],
["title":"Basketball"],
]
var titleArray: [String]
for (key, value) in arrSportsList {
print (key) // "title"
print (value) //Cricket, Soccer, American Football, Ice Hockey, Tennis, Baseball, Basketball
titleArray.append(value)
}
print (titleArray) //Cricket, Soccer, American Football, Ice Hockey, Tennis, Baseball, Basketball

How do I sort an array of dictionary according to an array contents in Swift

I have an array of dictionary. I need to sort that array. The sorting shouldnt be like ascending or descending but it should be based on an another array contents.
EX: Lets say I have an array nammed array_unsorted and that array contains a lot of dictionary objects like d1, d2, d3, d4 etc. Each of the dictionary object has a key called key1 and each dictionary object has different value for that key such as Kammy, Maddy, Jessy. Lets say I have anohter sorted array which Maddy, Kammy, Jessy. Now the dictionary should be sorted in a way that the first element should the dictionary object in which the value for key1 should beMaddy`.
I cannot use SortDescriptor, because this will sort as an ascending or descending order based on the key passed to it.
I have tried my solution but I am ended up using so many nested loops. I feel like the solution I made so so pathetic that I dont even want to post the code here.
Any help would be so much appreciated.
EDIT: There can be multiple sorting arrays but as of now I am considering only one sorting array and then I can write the code for multiple sorting arrays.
How about this:
Create a new, empty dictionary with a String key, and a value of type Dictionary. Call it sourceItemsDict.
Loop through the dictionaries in your source array, and add each entry to your new dictionary, using your sort key as the dictionary key, and put the array entry as the value.
Create a new, empty array of dictionaries for your sorted results. call it sortedArray.
Now loop through your array that has the desired order in it. Fetch the item with that key from sourceItemsDict and append it to the end of sortedArray.
That should do it, and it should perform in O(n) time.
Try this:
func sort<T: Equatable>(arrayOfDict arr: [[String: T]], by key: String, order: [T]) -> [[String: T]] {
return arr.sorted {
guard let value0 = $0[key], let value1 = $1[key] else {
return false
}
guard let index0 = order.index(of: value0), let index1 = order.index(of: value1) else {
return false
}
return index0 < index1
}
}
let array_unsorted = [
["name": "Kammy", "city": "New York"],
["name": "Maddy", "city": "Cupertino"],
["name": "Jessy", "city": "Mountain View"]
]
let sortedByName = sort(arrayOfDict: array_unsorted, by: "name", order: ["Maddy", "Kammy", "Jessy"])
let sortedByCity = sort(arrayOfDict: array_unsorted, by: "city", order: ["Cupertino", "Mountain View", "New York"])
print(sortedByName)
print(sortedByCity)
Your question leaves a couple of unresolved scenarios:
1: What if the key is missing from a dictionary?
let array_unsorted = [
["name": "Kammy", "city": "New York"],
["city": "Las Vegas"],
["name": "Maddy", "city": "Cupertino"],
["name": "Jessy", "city": "Mountain View"]
]
let sortedByName = sort(arrayOfDict: array_unsorted, by: "name", order: ["Maddy", "Kammy", "Jessy"])
Should Las Vegas appear at the beginning or end of the sorted array?
2: What if you don't specify an order for a value?
let array_unsorted = [
["name": "Amy"],
["name": "Kammy", "city": "New York"],
["name": "Maddy", "city": "Cupertino"],
["name": "Jessy", "city": "Mountain View"]
]
let sortedByName = sort(arrayOfDict: array_unsorted, by: "name", order: ["Maddy", "Kammy", "Jessy"])
Now where should Amy be placed?
Check out this example:
let dic1 = ["name" : "a"]
let dic2 = ["name" : "b"]
let dic3 = ["name" : "c"]
let dic4 = ["name" : "d"]
let dic5 = ["name" : "e"]
let unsorted_array = [dic2,dic5,dic1,dic4,dic3]
func sortArrayByName(_ array:[[String:String]])->[[String:String]]{
var sortedArray:[[String:String]] = [[String:String]]()
var sortingOrder:[String] = [String]()
for eachDic in array{
if let name = eachDic["name"]{
sortingOrder.append(name)
sortingOrder.sort() // sorting logic here
if sortedArray.isEmpty{
sortedArray.append(eachDic)
} else {
let index = sortingOrder.index(of: name)!
sortedArray.insert(eachDic, at: index)
}
}
}
return sortedArray
}
let sorted_array = sortArrayByName(unsorted_array)

How to append associative array elements in Swift

How do I create and append to an associative array in Swift? I would think it should be something like the following (note that some values are strings and others are numbers):
var myArray = []
var make = "chevy"
var year = 2008
var color = "red"
myArray.append("trackMake":make,"trackYear":year,"trackColor":color)
The goal is to be able to have an array full of results where I can make a call such as:
println(myArray[0]["trackMake"]) //and get chevy
println(myArray[0]["trackColor"]) //and get red
Simply like this:
myArray.append(["trackMake":make,"trackYear":year,"trackColor":color])
Add the brackets. This will make it a hash and append that to the array.
In such cases make (extensive) use of let:
let dict = ["trackMake":make,"trackYear":year,"trackColor":color]
myArray.append(dict)
The above assumes that your myArray has been declared as
var myArray = [[String:AnyObject]]()
so the compiler knows that it will take dictionary elements.
I accept above answer.It is good.Even you have given correct answer,I like to give simplest way.The following steps are useful,if you guys follow that.Also if someone new in swift and if they go through this,they can easily understand the steps.
STEP 1 : Declare and initialize the variables
var array = Array<AnyObject>()
var dict = Dictionary<String, AnyObject>()
var make = "chevy"
var year = 2008
var color = "red"
STEP 2 : Set the Dictionary(adding keys and Values)
dict["trackMake"] = make
dict["trackYear"] = year
dict["trackColor"] = color
println("the dict is-\(dict)")
STEP 3 : Append the Dictionary to Array
array.append(dict)
println("the array is-\(array)")
STEP 4 : Get Array values to variable(create the variable for getting value)
let getMakeValue = array[0]["trackMake"]
let getYearValue = array[0]["trackYear"]
let getColorValue = array[0]["trackColor"]
println("the getMakeValue is - \(getMakeValue)")
println("the getYearValue is - \(getYearValue)")
println("the getColorVlaue is - \(getColorValue)")
STEP 5: If you want to get values to string, do the following steps
var stringMakeValue:String = getMakeValue as String
var stringYearValue:String = ("\(getYearValue as Int)")
var stringColorValue:String = getColorValue as String
println("the stringMakeValue is - \(stringMakeValue)")
println("the stringYearValue is - \(stringYearValue)")
println("the stringColorValue is - \(stringColorValue)")
STEP 6 : Finally the total output values are
the dict is-[trackMake: chevy, trackColor: red, trackYear: 2008]
the array is-[{
trackColor = red;
trackMake = chevy;
trackYear = 2008;
}]
the getMakeValue is - Optional(chevy)
the getYearValue is - Optional(2008)
the getColorVlaue is - Optional(red)
the stringMakeValue is - chevy
the stringYearValue is - 2008
the stringColorValue is - red
Thank You
This sounds like you are wanting an array of objects that represent vehicles. You can either have an array of dictionaries or an array of vehicle objects.
Likely you will want to go with an object as Swift arrays and dictionaries must be typed. So your dictionary with string keys to values of differing types would end up having the type [String : Any] and you would be stuck casting back and forth. This would make your array of type [[String : Any ]].
Using an object you would just have an array of that type. Say your vehicle object's type is named Vehicle, that would make your array of type [Vehicle] and each array access would return an instance of that type.
If I want to try it with my own statement. Which also I want to extend my array with the data in my dictionary and print just the key from dictionary:
var myArray = ["Abdurrahman","Yomna"]
var myDic: [String: Any] = [
"ahmed": 23,
"amal": 33,
"fahdad": 88]
for index in 1...3 {
let dict: [String: Any] = [
"key": "new value"
]
// get existing items, or create new array if doesn't exist
var existingItems = myDic[myArray] as? [[String: Any]] ?? [[String: Any]]()
// append the item
existingItems.append(myArray)
// replace back into `data`
myDic[myArray] = existingItems
}

Create Dictionary<String, [SomeStruct]> from [SomeStruct] source-array

var sourceEntries: [Entry] = [entry1, ..., entry14]
var myDict: Dictionary<String, [Entry]> = [:]
for entry in sourceEntries {
if var array = myDict[entry.attribute1] { theArray.append(entry) }
else { myDict[entry.attribute1] = [entry] }
}
I am intending to create a Dictionary, which matches all the objects of the struct "Eintrag" with the same attribute from the source-Array "alleEinträge" to a String containing the value of the shared attribute. For some reason my final Dictionary just matches Arrays of one element to the Strings, although some Arrays ought to contain up to four elements.
The problem is that the array is passed by value (i.e. "copied"), so the array you are writing to when you say array.append is not the array that is "inside" the dictionary. You have to write back into the dictionary explicitly if you want to change what's in it.
Try it in a simple situation:
var dict = ["entry":[0,1,2]]
// your code
if var array = dict["entry"] { array.append(4) }
// so what happened?
println(dict) // [entry: [0, 1, 2]]
As you can see, the "4" never got into the dictionary.
You have to write back into the dictionary explicitly:
if var array = dict["entry"] { array.append(4); dict["entry"] = array }
FURTHER THOUGHTS: You got me thinking about whether there might be a more elegant way to do what you're trying to do. I'm not sure whether you will think this is "more elegant", but perhaps it has some appeal.
I will start by setting up a struct (like your Entry) with a name attribute:
struct Thing : Printable {
var name : String
var age : Int
var description : String {
return "{\(self.name), \(self.age)}"
}
}
Now I will create an array like your sourceEntries array, where some of the structs share the same name (like your shared attribute attribute1):
let t1 = Thing(name: "Jack", age: 40)
let t2 = Thing(name: "Jill", age: 38)
let t3 = Thing(name: "Jill", age: 37)
let arr = [t1,t2,t3]
And of course I will prepare the empty dictionary, like your myDict, which I call d:
var d = [String : [Thing]]()
Now I will create the dictionary! The idea is to use map and filter together to do all the work of creating key-value pairs, and then we just build the dictionary from those pairs:
let pairs : [(String, [Thing])] = arr.map {
t in (t.name, arr.filter{$0.name == t.name})
}
for pair in pairs { d[pair.0] = pair.1 }

Resources