I have this code
for (k, v) in myDict {
println(k)
}
How do I access the next key in the dictionary (e.g. myDict[k + 1])?
Thanks in advance!
There is no such thing as "the next key"; dictionaries have no order.
Since, however, you are iterating through the dictionary...
for (k, v) in myDict {
println(k)
}
I'm going to assume that what you mean is: how can I know, on this iteration, what k would be on the next iteration?
A simple solution would be to coerce the dictionary to an array (of key-value tuples):
let arr = Array(myDict)
Now you have something with integer indexes. So you can enumerate it like this:
let arr = Array(myDict)
for (ix, (k,v)) in enumerate(arr) {
println("This key is \(k)")
if ix < arr.count-1 {
println("The next key is \(arr[ix+1].0)")
}
}
The truth is, of course, that you can enumerate a dictionary directly, but indexes are not integers, so they are a little harder to work with. Martin R is also showing an approach illustrating that point.
I don't know if this is what you are looking for, but you can
iterate through a dictionary in a "similar" way as iterating
through an array by using the DictionaryIndex<Key, Value> as an index:
let dict = [ "foo" : 1, "bar" : 2, "baz" : 3]
for idx in indices(dict) {
let (k, v) = dict[idx]
println("Current key: \(k), current value: \(v)")
let nextIdx = idx.successor()
if nextIdx != dict.endIndex {
let (k1, v1) = dict[nextIdx]
println("Next key: \(k1), next value: \(v1)")
}
}
Sample output:
Current key: bar, current value: 2
Next key: baz, next value: 3
Current key: baz, current value: 3
Next key: foo, next value: 1
Current key: foo, current value: 1
A possible solution is to create Generator which returns the current and previous values in a sequence. For this you need a custom Generator which will return a tuple, containing the previous and current values from a sequence, from next:
struct PairGenerator<Base: GeneratorType> : GeneratorType {
typealias ElementPair = (previousElement: Base.Element, currentElement: Base.Element)
private var base: Base
private var previousElement: Base.Element?
init(_ base: Base) {
self.base = base
}
mutating func next() -> ElementPair? {
if previousElement == nil { previousElement = base.next() }
let currentElement = base.next()
// Since `base.next()` returns `nil` when the end of the sequence
// is reached, we need to check `previousElement` and `currentElement `
// aren't `nil`. If either of them are, `nil` will be returned to signal
// there aren't any pairs left.
if let prev = previousElement, curr = currentElement {
previousElement = currentElement
return (prev, curr)
}
return nil
}
}
The PairGenerator is then stored in a PairSequence, which conforms to SequenceType; this means you can iterate over it in a for loop.
struct PairSequence<Base: SequenceType> : SequenceType {
let generator: PairGenerator<Base.Generator>
init(_ base: Base) {
generator = PairGenerator(base.generate())
}
func generate() -> PairGenerator<Base.Generator> {
return generator
}
}
Now you need a function which will create a PairSequence from an object that conforms to SequenceType:
func pairs<Seq: SequenceType>(base: Seq) -> PairSequence<Seq> {
return PairSequence(base)
}
Finally, you can use this like so:
let myDict = ["1": 1, "2": 2, "3": 3, "4": 4]
let values = Array(myDict.values).sorted(<)
for (prev, curr) in pairs(values) {
println("\(prev), \(curr)")
}
// Prints:
// 1, 2
// 2, 3
// 3, 4
You could use pairs(myDict), but like #Martin R and #matt said - Dictionaries don't have an order so you may not get the results in the order you expected.
For more information on SequenceType and GeneratorType, I'd recommend looking at Playing With Swift and Generators In Swift.
Or, as #Martin R pointed out in his comment, you could use:
for (prev, curr) in zip(values, dropFirst(values)) {
println("\(prev), \(curr)")
}
Related
Struggling to achieve 2) below.
In the examples below, T is a concrete type. T could be String but the examples would then look even stranger.
Works:
var v = [ // v is a Dictionary with two Dictionary<String, T>.Element's
"x": T("x"), // Unfortunate since "x" has to be repeated
"y": T("y")
]
Desired syntax, intended to do the same as 1). Does not work:
var v = [
{ let s = "x"; // Attempting to use a closure to "inline" the local variable s
return (s: T(name: s)) // Using a tuple to return the Dictionary<String, T>.Element
}(),
{ let s = "y";
return (s: T(name: s))
}()
]
Xcode error for 2): Heterogeneous collection literal could only be inferred to '[Any]'; add explicit type annotation if this is intentional
Trying to fix 2) with explicit types. Does not work.
var v : Dictionary<String, T>.Element = [
{ let s = "x";
return Dictionary<String, T>.Element(s: T(name: s))
}(),
{ let s = "y";
return Dictionary<String, T>.Element(s: T(name: s))
}()
]
Xcode error for 3): Dictionary of type 'Dictionary<String, T>' cannot be initialized with array literal
This "MWE" example admittedly looks weird, but I am trying to understand how, in general, it may be possible to use a Dictionary Element (Key and Value together, as a hole) as if it were (informally speaking) an element of an Array.
If you have an array of keys and you want to create a dictionary out of it by mapping each key to another type, I'd suggest this way:
let keys = ["x", "y", "z"]
let dict = Dictionary(
uniqueKeysWithValues: keys.map { key in (key, T(key)) }
)
I am still not sure exactly what you want but I thought I add this solution to see if it is correct or at least something to discuss further
struct T {
let name: String
}
extension Dictionary where Key == String, Value == T {
init(values: Key...) {
self = values.reduce(into: [:]) { $0[$1] = T(name: $1) }
}
}
var dict = Dictionary(values: "x", "y")
An alternative solution when the init needs to be dynamic
extension Dictionary where Key == String, Value == T {
init(values: Key..., construct: (Key) -> T) {
self = values.reduce(into: [:]) { $0[$1] = construct($1) }
}
}
var dict = Dictionary(values: "x", "y") { T(name: $0)}
Sufficient solution:
var v = Dictionary<String, T>(uniqueKeysWithValues:
[ { let s = "x"; return (s, T(s)) }(),
{ let s = "y"; return (s, T(s)) }(),
]
)
That means, that you must use explicit Dictionary constructor, using uniqueKeysWithValues
I'm trying to compare element to next element in a collection.
For example :
let array: [(Double, String)]= [(2.3, "ok"),
(1.4, "ok"),
(5.1, "notOk")]
I need a returned array who will summary element where the string is the same. So my result will be :
new array = [(3.7, "ok"), (5.1, "notOk")]
I need to do it functional if possible. i tried to get next element in a map but can't found how.
Something like this (this is just for logic, this code isn't working.
let newArray = array.map {(element, nextElement) in
if element.1 == nextElement.1 {
return element.0 + nextElement.0
}
}
In a more functional way:
let array: [(Double, String)]= [(2.3, "ok"),
(1.4, "ok"),
(5.1, "notOk")]
let keys = Set(array.map{$0.1}) // find unique keys
let result = keys.map { key -> (Double, String) in
let sum = array.filter {$0.1 == key} // find all entries with the current key
.map {$0.0} // map them to their values
.reduce(0, +) // sum the values
return (sum, key)
}
print(result)
Output:
[(5.0999999999999996, "notOk"), (3.6999999999999997, "ok")]
Alternatively (suggested by #dfri):
let keys = Set(array.map{$0.1}) // find unique keys
let result = keys.map { key -> (Double, String) in
let sum = array.reduce(0) { $0 + ($1.1 == key ? $1.0 : 0) }
return (sum, key)
}
I like alexburtnik's answer. It's basically word for word how I wrote my first pass of this. It's straightforward, clear, and efficient. It is excellent Swift.
But functional programming can help us think more deeply about problems and create better, reusable tools. So let's think functionally.
dfri's solution appears beautiful, but is O(m*n) (in the worst case, O(n^2)). It loops through the entire array for every unique key. This gets back the old adage by Alan Perlis: "A Lisp programmer knows the value of everything and the cost of nothing." But functional programming doesn't have to be inefficient.
The point of functional programming is to break down complex problems into simpler problems, make those simpler problems generic, and then recombine them. It's not about filters and flatMaps.
So let's break down this problem. We want to group by key, and then sum the values for each key. Grouping by key is going to be a lot easier if we sort by key first:
let result = array
.sorted(by: { $0.1 < $1.1 })
Now, we wish we could group them with something like this:
let result = array
.sorted(by: { $0.1 < $1.1 })
.grouped(by: { $0.1 == $1.1 })
I wish I had that grouped(by:). Wish fulfillment is the heart of functional programming, so let's write it. Well, a group is a sequence of elements that are all "equal" for some value of "equal." We could build that this way:
extension Array {
func grouped(by equal: (Element, Element) -> Bool) -> [[Element]] {
guard let firstElement = first else { return [] }
guard let splitIndex = index(where: { !equal($0, firstElement) } ) else { return [self] }
return [Array(prefix(upTo: splitIndex))] + Array(suffix(from: splitIndex)).grouped(by: equal)
}
That said, I don't really like this code. It's not very Swifty. That [Array(prefix(...)] + is a good indication of how much Swift hates us doing it this way. And it can be very expensive due to copying (probably getting us back to O(n^2). The Swiftier solution would be an Sequence:
struct GroupedSequence<Element>: Sequence, IteratorProtocol {
var elements: [Element]
let equal: (Element, Element) -> Bool
private var nextIndex = 0
init(of elements: [Element], by equal: #escaping (Element, Element) -> Bool) {
self.elements = elements
self.equal = equal
}
mutating func next() -> ArraySlice<Element>? {
guard nextIndex < elements.endIndex else { return nil }
let first = elements[nextIndex]
let splitIndex = elements[nextIndex..<elements.endIndex].index(where: { !equal($0, first) } ) ?? elements.endIndex
defer { nextIndex = splitIndex }
return elements[nextIndex..<splitIndex]
}
}
extension Array {
func grouped(by equal: #escaping (Element, Element) -> Bool) -> GroupedSequence<Element> {
return GroupedSequence(elements: self, equal: equal)
}
}
Yes, it mutates and it's a little more code, but it's also lazy (which is a key tool from functional programming), it's better Swift, and very reusable. I like it. But you can use the recursive, pure version if you like.
OK, so now we have an array of arrays that are equivalent. We want to map over those and reduce each element to its sum. So we'll have a reduce inside a map. But this is not O(n^2) because each reduce is only over a single slice. We're going to walk every element just one time. To take care of one impossible corner case (an empty group, which grouped(by:) will never actually create), we'll use flatMap, but it's really just a map. You might be tempted to jump to this, but don't do it:
let result: [(Double, String)] = array
.sorted(by: { $0.1 < $1.1 })
.grouped(by: { $0.1 == $1.1 })
.flatMap { group in
guard let key = group.first?.1 else { return nil }
return (group.reduce(0, { $0 + $1.0 }), // Sum of our values
key)
}
Why? That's horribly unreadable. This is what gives functional programming a bad name. What the heck is that last piece doing? No, we want functional composition, not just functional tools. So we extract a function:
func sumEach(pairGroup: ArraySlice<(Double, String)>) -> (Double, String)? {
guard let key = pairGroup.first?.1 else { return nil }
return (pairGroup.reduce(0, { $0 + $1.0 }), // Sum of our values
key)
}
Now, we can have our nice functional approach without sacrificing comprehension:
let result = array
.sorted(by: { $0.1 < $1.1 })
.grouped(by: { $0.1 == $1.1 })
.flatMap(sumEach(pairGroup:))
And in the process we've created a new tool, grouping, that we can use to compose other solutions. I think that's pretty nice.
But I'd still probably do it alexburtnik's way.
You can iterate over every tupple in your input array and save a sum in a dictionary like this:
let array: [(Double, String)] = [(1.0,"notok"),(2.0,"ok"),(3.0,"ok"),(4.0,"ok"),(5.0,"ok"),(6.0,"ok"), (7.0,"notok")]
var dict = [String: Double]()
for (value, key) in array {
dict[key] = (dict[key] ?? 0) + value
}
print ("dict: \(dict)")
Output:
dict: ["notok": 8.0, "ok": 20.0]
If you really need to get an array of tuples, use this:
let result = dict.map { (key, value) in (value, key) }
print ("result: \(result)")
Output:
result: [(8.0, "notok"), (20.0, "ok")]
I guess that a solution that makes a good use of Swift's features would be to combine filter and reduce:
let array: [(String, Double)] = [("ok", 2.4),
("ok", 1.3),
("not ok", 4.4),
("very not ok", 99.0)]
let key = "ok"
let result = array.filter({$0.0 != key}) + [array.filter({ $0.0 == key }).reduce((key, 0.0), { (key, $0.1 + $1.1) })]
print(result)
And then the result would be
[("not ok", 4.4000000000000004), ("very not ok", 99.0), ("ok", 3.7000000000000002)]
Which I assume is what you wanted to achieve.
EDIT:
To reduce all tuples you could simply wrap the solution inside of a function:
func reduceAllTuples(tupleArray: [(String, Double)]) -> [(String, Double)]{
var array = tupleArray
for (key, _) in tupleArray {
array = array.filter({$0.0 != key}) + [array.filter({ $0.0 == key }).reduce((key, 0.0), { (key, $0.1 + $1.1) })]
}
return array
}
In Swift, how can I check if an element exists in an array? Xcode does not have any suggestions for contain, include, or has, and a quick search through the book turned up nothing. Any idea how to check for this? I know that there is a method find that returns the index number, but is there a method that returns a boolean like ruby's #include??
Example of what I need:
var elements = [1,2,3,4,5]
if elements.contains(5) {
//do something
}
Swift 2, 3, 4, 5:
let elements = [1, 2, 3, 4, 5]
if elements.contains(5) {
print("yes")
}
contains() is a protocol extension method of SequenceType (for sequences of Equatable elements) and not a global method as in
earlier releases.
Remarks:
This contains() method requires that the sequence elements
adopt the Equatable protocol, compare e.g. Andrews's answer.
If the sequence elements are instances of a NSObject subclass
then you have to override isEqual:, see NSObject subclass in Swift: hash vs hashValue, isEqual vs ==.
There is another – more general – contains() method which does not require the elements to be equatable and takes a predicate as an
argument, see e.g. Shorthand to test if an object exists in an array for Swift?.
Swift older versions:
let elements = [1,2,3,4,5]
if contains(elements, 5) {
println("yes")
}
For those who came here looking for a find and remove an object from an array:
Swift 1
if let index = find(itemList, item) {
itemList.removeAtIndex(index)
}
Swift 2
if let index = itemList.indexOf(item) {
itemList.removeAtIndex(index)
}
Swift 3, 4
if let index = itemList.index(of: item) {
itemList.remove(at: index)
}
Swift 5.2
if let index = itemList.firstIndex(of: item) {
itemList.remove(at: index)
}
Updated for Swift 2+
Note that as of Swift 3 (or even 2), the extension below is no longer necessary as the global contains function has been made into a pair of extension method on Array, which allow you to do either of:
let a = [ 1, 2, 3, 4 ]
a.contains(2) // => true, only usable if Element : Equatable
a.contains { $0 < 1 } // => false
Historical Answer for Swift 1:
Use this extension: (updated to Swift 5.2)
extension Array {
func contains<T>(obj: T) -> Bool where T: Equatable {
return !self.filter({$0 as? T == obj}).isEmpty
}
}
Use as:
array.contains(1)
If you are checking if an instance of a custom class or struct is contained in an array, you'll need to implement the Equatable protocol before you can use .contains(myObject).
For example:
struct Cup: Equatable {
let filled:Bool
}
static func ==(lhs:Cup, rhs:Cup) -> Bool { // Implement Equatable
return lhs.filled == rhs.filled
}
then you can do:
cupArray.contains(myCup)
Tip: The == override should be at the global level, not within your class/struct
I used filter.
let results = elements.filter { el in el == 5 }
if results.count > 0 {
// any matching items are in results
} else {
// not found
}
If you want, you can compress that to
if elements.filter({ el in el == 5 }).count > 0 {
}
Hope that helps.
Update for Swift 2
Hurray for default implementations!
if elements.contains(5) {
// any matching items are in results
} else {
// not found
}
(Swift 3)
Check if an element exists in an array (fulfilling some criteria), and if so, proceed working with the first such element
If the intent is:
To check whether an element exist in an array (/fulfils some boolean criteria, not necessarily equality testing),
And if so, proceed and work with the first such element,
Then an alternative to contains(_:) as blueprinted Sequence is to first(where:) of Sequence:
let elements = [1, 2, 3, 4, 5]
if let firstSuchElement = elements.first(where: { $0 == 4 }) {
print(firstSuchElement) // 4
// ...
}
In this contrived example, its usage might seem silly, but it's very useful if querying arrays of non-fundamental element types for existence of any elements fulfilling some condition. E.g.
struct Person {
let age: Int
let name: String
init(_ age: Int, _ name: String) {
self.age = age
self.name = name
}
}
let persons = [Person(17, "Fred"), Person(16, "Susan"),
Person(19, "Hannah"), Person(18, "Sarah"),
Person(23, "Sam"), Person(18, "Jane")]
if let eligableDriver = persons.first(where: { $0.age >= 18 }) {
print("\(eligableDriver.name) can possibly drive the rental car in Sweden.")
// ...
} // Hannah can possibly drive the rental car in Sweden.
let daniel = Person(18, "Daniel")
if let sameAgeAsDaniel = persons.first(where: { $0.age == daniel.age }) {
print("\(sameAgeAsDaniel.name) is the same age as \(daniel.name).")
// ...
} // Sarah is the same age as Daniel.
Any chained operations using .filter { ... some condition }.first can favourably be replaced with first(where:). The latter shows intent better, and have performance advantages over possible non-lazy appliances of .filter, as these will pass the full array prior to extracting the (possible) first element passing the filter.
Check if an element exists in an array (fulfilling some criteria), and if so, remove the first such element
A comment below queries:
How can I remove the firstSuchElement from the array?
A similar use case to the one above is to remove the first element that fulfils a given predicate. To do so, the index(where:) method of Collection (which is readily available to array collection) may be used to find the index of the first element fulfilling the predicate, whereafter the index can be used with the remove(at:) method of Array to (possible; given that it exists) remove that element.
var elements = ["a", "b", "c", "d", "e", "a", "b", "c"]
if let indexOfFirstSuchElement = elements.index(where: { $0 == "c" }) {
elements.remove(at: indexOfFirstSuchElement)
print(elements) // ["a", "b", "d", "e", "a", "b", "c"]
}
Or, if you'd like to remove the element from the array and work with, apply Optional:s map(_:) method to conditionally (for .some(...) return from index(where:)) use the result from index(where:) to remove and capture the removed element from the array (within an optional binding clause).
var elements = ["a", "b", "c", "d", "e", "a", "b", "c"]
if let firstSuchElement = elements.index(where: { $0 == "c" })
.map({ elements.remove(at: $0) }) {
// if we enter here, the first such element have now been
// remove from the array
print(elements) // ["a", "b", "d", "e", "a", "b", "c"]
// and we may work with it
print(firstSuchElement) // c
}
Note that in the contrived example above the array members are simple value types (String instances), so using a predicate to find a given member is somewhat over-kill, as we might simply test for equality using the simpler index(of:) method as shown in #DogCoffee's answer. If applying the find-and-remove approach above to the Person example, however, using index(where:) with a predicate is appropriate (since we no longer test for equality but for fulfilling a supplied predicate).
An array that contains a property that equals to
yourArray.contains(where: {$0.propertyToCheck == value })
Returns boolean.
The simplest way to accomplish this is to use filter on the array.
let result = elements.filter { $0==5 }
result will have the found element if it exists and will be empty if the element does not exist. So simply checking if result is empty will tell you whether the element exists in the array. I would use the following:
if result.isEmpty {
// element does not exist in array
} else {
// element exists
}
Swift 4/5
Another way to achieve this is with the filter function
var elements = [1,2,3,4,5]
if let object = elements.filter({ $0 == 5 }).first {
print("found")
} else {
print("not found")
}
As of Swift 2.1 NSArrays have containsObjectthat can be used like so:
if myArray.containsObject(objectImCheckingFor){
//myArray has the objectImCheckingFor
}
Array
let elements = [1, 2, 3, 4, 5, 5]
Check elements presence
elements.contains(5) // true
Get elements index
elements.firstIndex(of: 5) // 4
elements.firstIndex(of: 10) // nil
Get element count
let results = elements.filter { element in element == 5 }
results.count // 2
Just in case anybody is trying to find if an indexPath is among the selected ones (like in a UICollectionView or UITableView cellForItemAtIndexPath functions):
var isSelectedItem = false
if let selectedIndexPaths = collectionView.indexPathsForSelectedItems() as? [NSIndexPath]{
if contains(selectedIndexPaths, indexPath) {
isSelectedItem = true
}
}
if user find particular array elements then use below code same as integer value.
var arrelemnts = ["sachin", "test", "test1", "test3"]
if arrelemnts.contains("test"){
print("found") }else{
print("not found") }
Here is my little extension I just wrote to check if my delegate array contains a delegate object or not (Swift 2). :) It Also works with value types like a charm.
extension Array
{
func containsObject(object: Any) -> Bool
{
if let anObject: AnyObject = object as? AnyObject
{
for obj in self
{
if let anObj: AnyObject = obj as? AnyObject
{
if anObj === anObject { return true }
}
}
}
return false
}
}
If you have an idea how to optimize this code, than just let me know.
Swift
If you are not using object then you can user this code for contains.
let elements = [ 10, 20, 30, 40, 50]
if elements.contains(50) {
print("true")
}
If you are using NSObject Class in swift. This variables is according to my requirement. you can modify for your requirement.
var cliectScreenList = [ATModelLeadInfo]()
var cliectScreenSelectedObject: ATModelLeadInfo!
This is for a same data type.
{ $0.user_id == cliectScreenSelectedObject.user_id }
If you want to AnyObject type.
{ "\($0.user_id)" == "\(cliectScreenSelectedObject.user_id)" }
Full condition
if cliectScreenSelected.contains( { $0.user_id == cliectScreenSelectedObject.user_id } ) == false {
cliectScreenSelected.append(cliectScreenSelectedObject)
print("Object Added")
} else {
print("Object already exists")
}
what about using a hash table for the job, like this?
first, creating a "hash map" generic function, extending the Sequence protocol.
extension Sequence where Element: Hashable {
func hashMap() -> [Element: Int] {
var dict: [Element: Int] = [:]
for (i, value) in self.enumerated() {
dict[value] = i
}
return dict
}
}
This extension will work as long as the items in the array conform to Hashable, like integers or strings, here is the usage...
let numbers = Array(0...50)
let hashMappedNumbers = numbers.hashMap()
let numToDetect = 35
let indexOfnumToDetect = hashMappedNumbers[numToDetect] // returns the index of the item and if all the elements in the array are different, it will work to get the index of the object!
print(indexOfnumToDetect) // prints 35
But for now, let's just focus in check if the element is in the array.
let numExists = indexOfnumToDetect != nil // if the key does not exist
means the number is not contained in the collection.
print(numExists) // prints true
Swift 4.2 +
You can easily verify your instance is an array or not by the following function.
func verifyIsObjectOfAnArray<T>(_ object: T) -> Bool {
if let _ = object as? [T] {
return true
}
return false
}
Even you can access it as follows. You will receive nil if the object wouldn't be an array.
func verifyIsObjectOfAnArray<T>(_ object: T) -> [T]? {
if let array = object as? [T] {
return array
}
return nil
}
You can add an extension for Array as such:
extension Array {
func contains<T>(_ object: T) -> Bool where T: Equatable {
!self.filter {$0 as? T == object }.isEmpty
}
}
This can be used as:
if myArray.contains(myItem) {
// code here
}
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
}
Is there an elegant way to make a custom operator that updates a dictionary value?
More specifically, I want a prefix operator that increments the integer value corresponding to a given key:
prefix operator +> {}
prefix func +> //Signature
{
...
}
var d = ["first" : 10 , "second" : 33]
+>d["second"] // should update d to ["first" : 10 , "second" : 34]
This is feasible using the functional way. For example, to calculate the frequencies of elements in an array:
func update<K,V>(var dictionary: [K:V], key: K, value: V) -> [K:V] {
dictionary[key] = value
return dictionary
}
func increment<T>(dictionary: [T:Int], key: T) -> [T:Int] {
return update(dictionary, key: key, value: dictionary[key].map{$0 + 1} ?? 1)
}
func histogram<T>( s: [T]) -> [T:Int] {
return s.reduce([T:Int](), combine: increment)
}
let foo = histogram([1,4,3,1,4,1,1,2,3]) // [2: 1, 3: 2, 1: 4, 4: 2]
But I am trying to do the same thing using a custom operator
var d = ["first" : 10 , "second" : 33]
d["second"]?++
The operator could be implemented like this:
prefix operator +> {}
prefix func +> <I : ForwardIndexType>(inout i: I?) {
i?._successorInPlace()
}
var dict = ["a":1, "b":2]
+>dict["b"]
dict // ["b": 3, "a": 1]
Although I'm not sure how it would give you a frequencies function - I mean, if it's building a dictionary, it's not going to have any keys to begin with, so there won't be anything to increment. There are a bunch of cool ways to do it, though. Using the postfix ++, you can do this:
extension SequenceType where Generator.Element : Hashable {
func frequencies() -> [Generator.Element:Int] {
var result: [Generator.Element:Int] = [:]
for element in self {
result[element]?++ ?? {result.updateValue(1, forKey: element)}()
}
return result
}
}
Airspeed Velocity tweeted another cool way:
extension Dictionary {
subscript(key: Key, or or: Value) -> Value {
get { return self[key] ?? or }
set { self[key] = newValue }
}
}
extension SequenceType where Generator.Element : Hashable {
func frequencies() -> [Generator.Element:Int] {
var result: [Generator.Element:Int] = [:]
for element in self { ++result[element, or: 0] }
return result
}
}
Or, using an undocumented function:
extension SequenceType where Generator.Element : Hashable {
func frequencies() -> [Generator.Element:Int] {
var result: [Generator.Element:Int] = [:]
for el in self {result[el]?._successorInPlace() ?? {result[el] = 1}()}
return result
}
}
First, look for a way to do it using functions (not custom operators). You want a function that takes a reference to an item (from a dictionary) and updates its value... that calls for an inout parameter type.
func increment(inout n: Int) {
n++
}
var d = ["first" : 10 , "second" : 33]
increment(&d["first"]!)
print(d) // -> "[first: 11, second: 33]"
You don't have to care about the value being in a dictionary — inout takes any kind of reference and updates it directly. (This even goes for computed properties. You can pass one inout and it'll correctly go through the setter and getter as it reads and writes values.) And because you don't have to care about the dictionary, you don't really need to be generic — if you want a function that works on dictionaries with Ints, just make a function that works on Ints and let inout do the rest.
Now, custom operators are just functions, so make an operator of your function:
prefix operator +> {}
prefix func +>(inout n: Int) {
n++
}
You can't use exactly the syntax you were asking for to invoke it, though: dictionary lookups always result in Optional types, so you have to unwrap.
+>d["second"] // error
+>d["second"]! // but this works — operators automatically make params inout as needed
print(d) // -> "[first: 11, second: 34]"
This is a little uglier than you probably are looking for, but you can accomplish it using an unsafe mutable pointer in a generic overloaded operator:
prefix operator +> {}
prefix func +><T>( value:UnsafeMutablePointer<T?> )
{
print( value.memory )
if let intValue = value.memory as? Int {
value.memory = (intValue + 1) as? T
}
}
var d = ["first" : 10 , "second" : 33]
print( d["second"] ) // Optional(33)
+>(&d["second"])
print( d["second"] ) // Optional(34)