Repeat a specific item of an array - swift

How to replace or repeat a specific item (v) of an array in Swift 3 / 4:
["A","s","B","v","C","s","D","v","E","s"]
to get this:
["A","s","B","v","v","C","s","D","v","v","E","s"]
or this:
["A","s","B","v","v","v","C","s","D","v","v","v","E","s"]
["A","s","B","v","v","v","v","C","s","D","v","v","v","v","E","s"]
The reason is that element v inserts pauses (sec) between audio files (A, B, C, ...). The number of repetitions of the item v should be set via a SegmentedControl (1,2, ..., 6).

Quick takeaway
extension Array where Element == String {
func repeatItem(_ item: Element, times n: Int) -> Array<Element> {
return flatMap { $0 == item ? Array(repeating: $0, count: n) : [$0] }
}
}
Detail explains
Use flatMap:
yourArray.flatMap { $0 == "v" ? [$0, $0] : [$0] }
Basically, this checks each element of the array. If it is "v", turn it into ["v", "v"]. If it is not "v", turn it into an array with that single element. Then it flattens all those arrays, hence flatMap.
You can also triple a specific item:
yourArray.flatMap { $0 == "v" ? [$0, $0, $0] : [$0] }
Or repeat it n times:
yourArray.flatMap { $0 == "v" ? Array(repeating: $0, count: n) : [$0] }
Use playground to verify it:
//: Playground - noun: a place where people can play
import Foundation
var inputArray = ["A","s","B","v","C","s","D","v","E","s"]
var expectArray2 = ["A","s","B","v","v","C","s","D","v","v","E","s"]
var expectArray3 = ["A","s","B","v","v","v","C","s","D","v","v","v","E","s"]
var expectArray4 = ["A","s","B","v","v","v","v","C","s","D","v","v","v","v","E","s"]
extension Array where Element == String {
func repeatItem(_ item: Element, times n: Int) -> Array<Element> {
return flatMap { $0 == item ? Array(repeating: $0, count: n) : [$0] }
}
}
print(inputArray.repeatItem("v", times: 2) == expectArray2)
print(inputArray.repeatItem("v", times: 3) == expectArray3)
print(inputArray.repeatItem("v", times: 4) == expectArray4)

You can use insert(:at:) using the specific index of an element.
var foo = [0,1,2,3,4,5,6,7]
foo.insert(0, at: foo[0])
Output
[0, 0, 1, 2, 3, 4, 5, 6, 7]
You can wrap this in a function to repeat as much as you need.

let array : [String] = ["A","s","B","v","C","s","D","v","E","s"]
print(replaceItem(array: array, item: "v"))
//Method
func replaceItem(array : [String], item : String) -> [String] {
var newAr: [String] = []
for arItem in array{
newAr.append(arItem)
if arItem == item {
newAr.append(arItem)
}
}
return newAr
}
output :
["A", "s", "B", "v", "v", "C", "s", "D", "v", "v", "E", "s"]

Related

How to perform sorting on an array without using .sort()

I am trying to find the easiest way to sort an array without using sort() function. I tried searching but i could not find any questions that were on SWIFT. I found several questions about php and javascript and so far nothing on swift.
var arr = [7,6456,2135,164,1345,4,8,5,87456,123,2,87,724,6523,1]
var arrSorted = arr
var index = arr.count
repeat {
var previousSwapIndex = 0
for i in 1..<index {
if (arrSorted[i - 1] as! Int) > (arrSorted[i] as! Int) {
let prevVal = arrSorted[i - 1]
let currentVal = arrSorted[i]
arrSorted[i] = prevVal
arrSorted[i - 1] = currentVal
previousSwapIndex = i
}
}
index = previousSwapIndex
} while (index != 0)
print(arrSorted as Array)
This method works but i am looking for something that is better than this and easier than this.
(Edit[Clarification] :- better = faster / quicker ,as this iterates 120 times before the array is sorted)
Could someone help me out?
Here's a generic implementation of insertion sort in Swift. It takes an inout array, but you should be able to modify it to return an array if that's what you want.
func sort<T: Comparable>(_ array: inout [T]) {
var i = 1
while i < array.count {
var x = array[i]
var j = i - 1
while j >= 0 && array[j] > x {
array[j+1] = array[j]
j -= 1
}
array[j+1] = x
i += 1
}
}
To use it:
var intArr = [1, 7, 3, 6, 4]
sort(&intArr)
print(intArr) // [1, 3, 4, 6, 7]
var stringArr = ["hello", "goodbye", "a", "string", "z", "another string"]
sort(&stringArr)
print(stringArr) // ["a", "another string", "goodbye", "hello", "string", "z"]
It will work on any type that conforms to Comparable.
You can find about all the different methods of sorting from this git.
https://github.com/raywenderlich/swift-algorithm-club
I checked a few and none of them are using any .sort() functions. Pick whichever feels easier for you.
var unsortedStringArray = ["B", "C", "Z", "A", "H"]
var unsortedIntArray = [7,8,3,4,5,9,1,2,6]
func sortFunction<T:Comparable>(array: [T]) -> [T]{
var unsortedArray = array
for i in 0..<unsortedArray.count {
for j in 0..<unsortedArray.count{
var temp: T
if unsortedArray[i] < unsortedArray[j] {
temp = unsortedArray[i]
unsortedArray[i] = unsortedArray[j]
unsortedArray[j] = temp
}
}
}
return unsortedArray
}
let resultStringArray = sortFunction(array: unsortedStringArray)
let resultIntArray = sortFunction(array: unsortedIntArray)
print(resultStringArray) //["A", "B", "C", "H", "Z"]
print(resultIntArray) // [1, 2, 3, 4, 5, 6, 7, 8, 9]

Looping through a multidimensional array in swift

So I am trying to iterate over an NSArray. My NSArray is an array of an array of strings. Here is a copy-paste of the first 1.5 elements
(
(
"Tater Tot Nachos",
"Fried Feta",
"The Ultimate Feta Bread",
"Cheese Bread",
"Aubrees Bread",
"The Wings!",
"Coconut Grove Chicken Sicks",
"Far East Wings",
"Bacon Brussels Sprouts"
),
(
"Shaved Brussels Sprout Salad",
"Greek Salad",
"Coronado Cobb Salad",
"Harvest Salad",
This is the function that's giving me the headache
func createMenu() {
if let list = cellDescripters {
for(index, item) in list.enumerated() {
for food in item {
//DO SOMETHING WITH "FOOD"
}
}
}
}
' cellDescripters ' Is a global variable and it is the array I was outlining at the top, basically an array of arrays of strings.
When I print the type of ' item ' I see it's of type __NSArrayM which is an NSMutableArray from my understanding. Looking at documentation NSMutableArrays are iterable.
However when I go to compile this code I get the error:
Type 'Any' does not conform to protocol 'Sequence'
Any help would be greatly appreciated.
I think following example give you help
for example i have array of string array like you =
[["beverages", "food", "suppliers"],["other stuff", "medicine"]];
var arrayExample = [["beverages", "food", "suppliers"],["other stuff", "medicine"]];
//Iterate array through for loop
for(index, item) in arrayExample.enumerated()
{
for food in item
{
print("index : \(index) item: \(food)")
}
}
OUTPUT
index : 0 item: beverages
index : 0 item: food
index : 0 item: suppliers
index : 1 item: other stuff
index : 1 item: medicine
Here's a more generic solution for iterating 2D arrays in Swift. Tested in Swift 4 on iOS 13.
Works only on Swift arrays, see the following link for converting your NSArray to Arrays: https://stackoverflow.com/a/40646875/1960938
// 2D array extension explanation: https://stackoverflow.com/a/44201792/1960938
fileprivate extension Array where Element : Collection, Element.Index == Int {
typealias InnerCollection = Element
typealias InnerElement = InnerCollection.Iterator.Element
func matrixIterator() -> AnyIterator<InnerElement> {
var outerIndex = self.startIndex
var innerIndex: Int?
return AnyIterator({
guard !self.isEmpty else { return nil }
var innerArray = self[outerIndex]
if !innerArray.isEmpty && innerIndex == nil {
innerIndex = innerArray.startIndex
}
// This loop makes sure to skip empty internal arrays
while innerArray.isEmpty || (innerIndex != nil && innerIndex! == innerArray.endIndex) {
outerIndex = self.index(after: outerIndex)
if outerIndex == self.endIndex { return nil }
innerArray = self[outerIndex]
innerIndex = innerArray.startIndex
}
let result = self[outerIndex][innerIndex!]
innerIndex = innerArray.index(after: innerIndex!)
return result
})
}
}
An example usage:
let sampleMatrix = [
["a", "b", "c"],
["d", "e"],
[],
["f"],
[]
]
// Should print: a, b, c, d, e, f
for element in sampleMatrix.matrixIterator() {
print(element)
}

Extract the elements from array and put back them to another array.?

suppose i have a array that have 10 elements. say,
var ArrayElemts : ["1","2","3","4","5","6","7","8","9","10","11"]
Now how can i keep the elements from 0 t0 5 in one array set and 6 to 10 to another array set?
Use [0...5] to create an ArraySlice and then Array to convert that back to an array:
var arrayElemts = ["1","2","3","4","5","6","7","8","9","10","11"]
let first = Array(arrayElemts[0...5])
let second = Array(arrayElemts[6...10])
print(first) // ["1", "2", "3", "4", "5", "6"]
print(second) // ["7", "8", "9", "10", "11"]
The easiest option is the following:
let partition1 = array.filter { Int($0) ?? 0 <= 5 }
let partition2 = array.filter { Int($0) ?? 0 > 5 }
Conversion to numbers should be the first step though. You should never work with strings as if they were numbers.
let numbers = array.flatMap { Int($0) }
let partition1 = numbers.filter { $0 <= 5 }
let partition2 = numbers.filter { $0 > 5 }
If we suppose the array is sorted, there are easier options:
let sorted = numbers.sorted()
let partition1: [Int]
let partition2: [Int]
if let partition2start = sorted.index(where: { $0 > 5 }) {
partition1 = Array(sorted.prefix(upTo: partition2start))
partition2 = Array(sorted.suffix(from: partition2start))
} else {
partition1 = sorted
partition2 = []
}
which is what the native partition method can do:
var numbers = array.flatMap { Int($0) }
let index = numbers.partition { $0 > 5 }
let partition1 = Array(numbers.prefix(upTo: index))
let partition2 = Array(numbers.suffix(from: index))
Note the method changes the original array.
Breaking the array up into N-sized chunks
The other answers show you how to "statically" partition the original array in different arrays using ArraySlice:s. Given your description, possibly you want to, generally, break up your original array into N-sized chunks (here: n = 5).
We could use the sequence(state:next) to implement such a chunk(bySize:) method as an extension to Collection:
extension Collection {
func chunk(bySize size: IndexDistance) -> [SubSequence] {
precondition(size > 0, "Chunk size must be a positive integer.")
return sequence(
state: (startIndex, index(startIndex, offsetBy: size, limitedBy: endIndex) ?? endIndex),
next: { indices in
guard indices.0 != self.endIndex else { return nil }
indices.1 = self.index(indices.0, offsetBy: size, limitedBy: self.endIndex) ?? self.endIndex
return (self[indices.0..<indices.1], indices.0 = indices.1).0
}).map { $0 }
}
}
Applied to your example:
var arrayElements = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11"]
let partitions = arrayElements.chunk(bySize: 5)
/* [["1", "2", "3", "4", "5"],
["6", "7", "8", "9", "10"],
["11"]] */
The chunk(bySize:) method will break up the array into bySize-sized chunks, as well as (possible) a smaller chunk for the final partition.
However, as much as I'd like to try to use the sequence(state:next) function (not needing to use any mutable intermediate variables other than state), the implementation above is quite bloated and difficult to read, so (as for so many other cases ...) we are probably better off simply using a while loop:
extension Collection {
func chunk(bySize size: IndexDistance) -> [SubSequence] {
precondition(size > 0, "Chunk size must be a positive integer.")
var chunks: [SubSequence] = []
var from = startIndex
while let to = index(from, offsetBy: size, limitedBy: endIndex) {
chunks.append(self[from..<to])
from = to
}
if from != endIndex { chunks.append(self[from..<endIndex]) }
return chunks
}
}
lol I don't see why there are so complicated answers here
(Consider the "array" variable as is -> [Int], not [Any])
So the first approach is just for Number types.
The second one should do it
Simply:
let array = [0,1,2,3,4,5,6,7,8,9,10]
//For instance..
var arrayA = ["A","B","C","D","E","F","G"]
//First 6 elements
let arrayOfFirstFour = array.filter({
return $0 <= 5 ? true : false
})
//Remaining elements:
let restOfArray = array.filter({
return $0 > 5 ? true : false
})
let elementsToFourth = arrayA.prefix(upTo: 4)
let elementsAfterFourth = arrayA.suffix(from: 4)
print(arrayOfFirstFour)
print(restOfArray)
print(elementsToFourth)
print(elementsAfterFourth)
//[0, 1, 2, 3, 4, 5]
//[6, 7, 8, 9, 10]
//["A", "B", "C", "D"]
//["E", "F", "G"]

Group dictionary by key in Swift

I'm trying to implement a groupBy functionality where all the numbers of a nested list are grouped. My code so far:
struct MyClass {
var numbers: [Int]
...
}
var dict: [String : MyClass] = ...
let numbers = dict
.filter{ $0.0.containsString(searchString) }
.flatMap{ $0.1.numbers }
This yields me an Array of Ints. However I'd like to have a dictionary [Int : Int] with each unique number and the count of its occurence. So for example:
[1,2,3,4,1,2,2,1]
should be:
[1 : 2, 2 : 3, 3 : 1, 4 : 1]
I know there's a groupBy operator, but Swift doesn't seem to have one. I've tried with reduce:
func reducer(accumulator: [Int: Int], num: Int) -> [Int : Int] {
var acc = accumulator
acc[num]! += 1
return acc
}
filtered.reduce([:], combine: reducer)
But it crashes when I want to run it. Not sure why, I get a EXC_BAD_INSTRUCTION.
I'd appreciate any help.
let numbers = [1,2,3,4,1,2,2,1]
var results = [Int: Int]()
Set(numbers).forEach { number in results[number] = numbers.filter { $0 == number }.count }
print(results) // [2: 3, 3: 1, 1: 3, 4: 1]
Actually I'm not very sure if this is what you want. I just looked at your examples.
Using NSCountedSet:
var objects = [1,2,3,4,1,2,2,1]
let uniques = NSCountedSet(array: objects)
uniques.forEach { results[$0 as! Int] = uniques.countForObject($0) }
print(results) // [2: 3, 3: 1, 1: 3, 4: 1]
I would expect the crash to be ocurring on this line:
acc[num]! += 1
The first time this is called for a number, the entry doesn't exist in the dictionary yet so acc[num] is nil. Forcefully unwrapping it would cause a crash.
Not sure if this is the best solution but you can simple check for this case:
if (acc[num]) {
acc[num]! += 1
} else {
acc[num] = 1
}
Cleaner code from #vacawama in the comments:
acc[num] = (acc[num] ?? 0) + 1
Here's an extension to Array that does what you're asking:
extension Array where Element: Hashable {
var grouped: [Element:Int] {
var dict = [Element:Int]()
self.forEach { dict[$0] = (dict[$0] ?? 0) + 1 }
return dict
}
}
The key is the closure: { dict[$0] = (dict[$0] ?? 0) + 1 }.
It takes the current value in the array, tests to see if it's a key in the dictionary, returns the value for that key if it exists or 0 if it doesn't, then adds one and sets the key:value to be the pair of the current value and occurrences so far.
Example use:
[1,2,3,4,1,2,2,1].grouped // => [2: 3, 3: 1, 1: 3, 4: 1]
You need something like this:
if let _ = acc.indexForKey(num) {
acc[num]! += 1
}
else {
acc[num] = 1
}
It's sort of unclear what you're asking for, but here's a function that will take an array of ints and return a dictionary with the number as the key, and the count as the value:
func getDictionaryOfCounts(accumulator: [Int]) -> [Int : Int] {
var countingDictionary: [Int : Int] = [:]
accumulator.forEach { (value) in
if countingDictionary[value] != nil {
countingDictionary[value]! += 1
}
else{
countingDictionary[value] = 1
}
}
return countingDictionary
}

Sort Dictionary by values in Swift

Is there are analog of - (NSArray *)keysSortedByValueUsingSelector:(SEL)comparator in swift?
How to do this without casting to NSDictionary?
I tried this, but it seems to be not a good solution.
var values = Array(dict.values)
values.sort({
$0 > $1
})
for number in values {
for (key, value) in dict {
if value == number {
println(key + " : \(value)");
dict.removeValueForKey(key);
break
}
}
}
Example:
var dict = ["cola" : 10, "fanta" : 12, "sprite" : 8]
dict.sortedKeysByValues(>) // fanta (12), cola(10), sprite(8)
Just one line code to sort dictionary by Values in Swift 4, 4.2 and Swift 5:
let sortedByValueDictionary = myDictionary.sorted { $0.1 < $1.1 }
Try:
let dict = ["a":1, "c":3, "b":2]
extension Dictionary {
func sortedKeys(isOrderedBefore:(Key,Key) -> Bool) -> [Key] {
return Array(self.keys).sort(isOrderedBefore)
}
// Slower because of a lot of lookups, but probably takes less memory (this is equivalent to Pascals answer in an generic extension)
func sortedKeysByValue(isOrderedBefore:(Value, Value) -> Bool) -> [Key] {
return sortedKeys {
isOrderedBefore(self[$0]!, self[$1]!)
}
}
// Faster because of no lookups, may take more memory because of duplicating contents
func keysSortedByValue(isOrderedBefore:(Value, Value) -> Bool) -> [Key] {
return Array(self)
.sort() {
let (_, lv) = $0
let (_, rv) = $1
return isOrderedBefore(lv, rv)
}
.map {
let (k, _) = $0
return k
}
}
}
dict.keysSortedByValue(<)
dict.keysSortedByValue(>)
Updated:
Updated to the new array syntax and sort semantics from beta 3. Note that I'm using sort and not sorted to minimize array copying. The code could be made more compact, by looking at the earlier version and replacing sort with sorted and fixing the KeyType[] to be [KeyType]
Updated to Swift 2.2:
Changed types from KeyType to Key and ValueType to Value. Used new sort builtin to Array instead of sort(Array) Note performance of all of these could be slightly improved by using sortInPlace instead of sort
You could use something like this perhaps:
var dict = ["cola" : 10, "fanta" : 12, "sprite" : 8]
var myArr = Array(dict.keys)
var sortedKeys = sort(myArr) {
var obj1 = dict[$0] // get ob associated w/ key 1
var obj2 = dict[$1] // get ob associated w/ key 2
return obj1 > obj2
}
myArr // ["fanta", "cola", "sprite"]
This should give you the sorted keys based on value, and is a little more cleaner:
var sortedKeys = Array(dict.keys).sorted(by: { dict[$0]! < dict[$1]! })
I think this is the easiest way to sort Swift dictionary by value.
let dict = ["apple":1, "cake":3, "banana":2]
let byValue = {
(elem1:(key: String, val: Int), elem2:(key: String, val: Int))->Bool in
if elem1.val < elem2.val {
return true
} else {
return false
}
}
let sortedDict = dict.sort(byValue)
OneLiner :
let dict = ["b": 2, "a": 1, "c": 3]
(Array(dict).sorted { $0.1 < $1.1 }).forEach { (k,v) in print("\(k):\(v)") }
//Output: a:1, b:2, c:3
Swap out the .forEach with .map -> Functional programming
Syntactical sugar :
extension Dictionary where Value: Comparable {
var sortedByValue: [(Key, Value)] { return Array(self).sorted { $0.1 < $1.1} }
}
extension Dictionary where Key: Comparable {
var sortedByKey: [(Key, Value)] { return Array(self).sorted { $0.0 < $1.0 } }
}
["b": 2, "a": 1, "c": 3].sortedByKey // a:1, b:2, c:3
["b": 2, "a": 1, "c": 3].sortedByValue // a:1, b:2, c:3
Lots of answers, here's a one-liner. I like it because it makes full use of native Swift iterative functions and doesn't use variables. This should help the optimiser do its magic.
return dictionary.keys.sort({ $0 < $1 }).flatMap({ dictionary[$0] })
Note the use of flatMap, because subscripting a dictionary returns an optional value. In practice this should never return nil since we get the key from the dictionary itself. flatMap is there only to ensure that the result is not an array of optionals. If your array's associated value should BE an optional you can use map instead.
Sorting your keys by the dictionary's value is actually simpler than it appears at first:
let yourDict = ["One": "X", "Two": "B", "Three": "Z", "Four": "A"]
let sortedKeys = yourDict.keys.sort({ (firstKey, secondKey) -> Bool in
return yourDict[firstKey] < yourDict[secondKey]
})
And that's it! There's really nothing more to it. I have yet to find a quicker method, other than the same approach in form of a simple one-liner:
let yourDict = ["One": "X", "Two": "B", "Three": "Z", "Four": "A"]
let sortedKeys = yourDict.keys.sort { yourDict[$0] < yourDict[$1] }
Sorting a dictionary by key or value
Using Swift 5.2 internal handling of "sorted":
var unsortedDict = ["cola" : 10, "fanta" : 12, "sprite" : 8]
// sorting by value
let sortedDictByValue = unsortedDict.sorted{ $0.value > $1.value } // from lowest to highest using ">"
print("sorted dict: \(sortedDictByValue)")
// result: "sorted dict: [(key: "fanta", value: 12), (key: "cola", value: 10), (key: "sprite", value: 8)]\n"
// highest value
print(sortedDictByValue.first!.key) // result: fanta
print(sortedDictByValue.first!.value) // result: 12
// lowest value
print(sortedDictByValue.last!.key) // result: sprite
print(sortedDictByValue.last!.value) // result: 8
// by index
print(sortedDictByValue[1].key) // result: cola
print(sortedDictByValue[1].value) // result: 10
// sorting by key
let sortedDictByKey = unsortedDict.sorted{ $0.key < $1.key } // in alphabetical order use "<"
// alternative:
// let sortedDictByKey = unsortedDict.sorted{ $0 < $1 } // without ".key"
print("sorted dict: \(sortedDictByKey)")
// result: "sorted dict: [(key: "cola", value: 10), (key: "fanta", value: 12), (key: "sprite", value: 8)]\n"
// highest value
print(sortedDictByKey.first!.key) // result: cola
print(sortedDictByKey.first!.value) // result: 10
// lowest value
print(sortedDictByKey.last!.key) // result: sprite
print(sortedDictByKey.last!.value) // result: 8
// by index
print(sortedDictByKey[1].key) // result: fanta
print(sortedDictByKey[1].value) // result: 12
The following might be useful if you want the output to be an array of key value pairs in the form of a tuple, sorted by value.
var dict = ["cola" : 10, "fanta" : 12, "sprite" : 8]
let sortedArrByValue = dict.sorted{$0.1 > $1.1}
print(sortedArrByValue) // output [(key: "fanta", value: 12), (key: "cola", value: 10), (key: "sprite", value: 8)]
Since Swift 3.0 Dictionary has sorted(by:) function which returns an array of tuples ([(Key, Value)]).
let sorted = values.sorted(by: { (keyVal1, keyVal2) -> Bool in
keyVal1.value > keyVal2.value
})
Just cast it to NSDictionary and then call the method. Anywhere you use #selector in ObjC you can just use a String in Swift. So it would look like this:
var dict = ["cola" : 10, "fanta" : 12, "sprite" : 8]
let sortedKeys = (dict as NSDictionary).keysSortedByValueUsingSelector("compare:")
or
let sortedKeys2 = (dict as NSDictionary).keysSortedByValueUsingComparator
{
($0 as NSNumber).compare($1 as NSNumber)
}
As of Swift 3, to sort your keys based on values, the below looks promising:
var keys = Array(dict.keys)
keys.sortInPlace { (o1, o2) -> Bool in
return dict[o1]! as! Int > dict[o2]! as! Int
}
var dict = ["cola" : 10, "fanta" : 12, "sprite" : 8]
let arr = dic.sort{ (d1,d2)-> Bool in
if d1.value > d2.value {
retrn true
}
}.map { (key,value) -> Int in
return value
}
Take look a clean implementation way.
print("arr is :(arr)")
The following way in Swift 3 sorted my dictionary by value in the ascending order:
for (k,v) in (Array(dict).sorted {$0.1 < $1.1}) {
print("\(k):\(v)")
}
SWIFT 3:
Using a few resources I put this beautifully short code together.
dictionary.keys.sorted{dictionary[$0]! < dictionary[$1]!}
This returns an array of the dictionary keys sorted by their values. It works perfectly & doesn't throw errors when the dictionary is empty. Try this code in a playground:
//: Playground - noun: a place where people can play
import UIKit
let dictionary = ["four": 4, "one": 1, "seven": 7, "two": 2, "three": 3]
let sortedDictionary = dictionary.keys.sorted{dictionary[$0]! < dictionary[$1]!}
print(sortedDictionary)
// ["one", "two", "three", "four", "seven"]
let emptyDictionary = [String: Int]()
let emptyDictionarySorted = emptyDictionary.keys.sorted{emptyDictionary[$0]! < emptyDictionary[$1]!}
print(emptyDictionarySorted)
// []
If you'd like some help on why the heck the code uses $0, $1 and doesn't even have parentheses after the "sorted" method, check out this post - https://stackoverflow.com/a/34785745/7107094
This is how I did it - sorting in this case by a key called position. Try this in a playground:
var result: [[String: AnyObject]] = []
result.append(["name" : "Ted", "position": 1])
result.append(["name" : "Bill", "position": 0])
result
result = sorted(result, positionSort)
func positionSort(dict1: [String: AnyObject], dict2: [String: AnyObject]) -> Bool {
let position1 = dict1["position"] as? Int ?? 0
let position2 = dict2["position"] as? Int ?? 0
return position1 < position2
}
Sorting the dictionary with a dictionary as the value (Nested dictionary)
var students: [String: [String: Any?]] = ["16CSB40" : ["Name": "Sunitha", "StudentId": "16CSB40", "Total": 90], "16CSB41" : ["Name": "Vijay", "StudentId": "16CSB40", "Total": 80], "16CSB42" : ["Name": "Tony", "StudentId": "16CSB42", "Total": 95]] // Sort this dictionary with total value
let sorted = students.sorted { (($0.1["Total"] as? Int) ?? 0) < (($1.1["Total"] as? Int) ?? 0) }
print(sorted) //Sorted result
Use this, and then just loop through the dictionary again using the output keys.
extension Dictionary where Value: Comparable {
func sortedKeysByValue() -> [Key] {
keys.sorted { return self[$0]! < self[$1]! }
}
}
...or this if you hate force unwrapping :)
extension Dictionary where Value: Comparable {
func sortedKeysByValue() -> [Key] {
keys.sorted { (key1, key2) -> Bool in
guard let val1 = self[key1] else { return true }
guard let val2 = self[key2] else { return true }
return val1 < val2
}
}
}