I'd like to create a generic find() typically used in functional programming. In functional programming you don't work with array indices and for loops. You filter. The way it works is that if you have a list of say
["apple", "banana", "cherry"]
and you want to find banana then you assign the array indices to the list elements by creating tuples
[(1, "apple"), (2, "banana"), (3, "cherry")]
Now you can filter down to "banana" and return the index value.
I was trying to create a generic function for this but I get an error. What's wrong with this syntax?
func findInGenericIndexedList<T>(indexedList: [(index: Int, value: T)], element: (index: Int, value: T)) -> Int? {
let found = indexedList.filter { // ERROR: Cannot invoke 'filter' with an argument list of type '((_) -> _)'
element.value === $0.value
}
if let definiteFound = found.first {
return definiteFound.index
}
return nil
}
UPDATE 1: I would like to use the above solution as opposed to using find() (will be deprecated) or in Swift 2.0 indexOf() because I'm trying to follow the Functional Programming paradigm, relying on general functions and not class methods.
The minimum change required to make this work would be to make T conform to Equatable and use the == operator.
func findInGenericIndexedList<T:Equatable>(indexedList: [(index: Int, value: T)], element: (index: Int, value: T)) -> Int? {
let found = indexedList.filter {
element.value == $0.value
}
if let definiteFound = found.first {
return definiteFound.index
}
return nil
}
It doesn't really make sense to use === here because are usually going to be applying this to value types (especially if you are following functional paradigms) for which this is never true.
Beyond this I spent some time thinking about the problem and here is what I would do:
extension Array where Element : Equatable {
func find(element:Array.Generator.Element) -> Int? {
let indexedList = lazy(self.enumerate())
let found = indexedList.filter {
element == $1
}
let definiteFound = found.prefix(1)
return definiteFound.generate().next()?.index
}
}
Protocol extension on Array because it makes the syntax neater, lazy sequence to avoid checking every element, 0 indexed.
Here are a couple of thoughts.
I would still prefer to use the identity operator '===', because in my array I may have multiple items of the same value.
The identity operator === only works for reference types, like classes. It will never work for value types, like Strings or Ints, or structs, etc. You might take a look at the difference between value types and reference types, especially if you are interested in functional programming, which eschews reference types almost completely. When you are working with value types, there is only equality (==) - there is no identity. Two instances of the String "bananas" will never refer to the same identical object. They will always refer to two different Strings, though their values might be equal.
I want to delete the exact item that I passed to the function. Is it impossible to do this?
If you are working with value types, like Strings, then yes, it is impossible. There is no such thing as two different Strings that are the exact same item. Two Strings are always are always different objects, for the reasons stated above.
Note that if you work only with classes, and not value types, then you could use the === operator, but this would defeat much of what you are trying to do.
What this boils down to is that if you have an array of (index, value) tuples that looks like this:
[(0, "bananas"), (1, "apples"), (2, "oranges"), (3, "bananas")]
And you write a function that looks for tuples where the value is "bananas", you have a couple of choices. You can filter it and look for the first tuple in the array that has the value "bananas" and return the index of that tuple. In the above case it would return 0. Or, you could return all of the indexes in the form of an array, like this: [0, 3]. Or I suppose you could return some other arbitrary subset of the results, like the last index, or the first-and-last indexes, etc., but those all seem a little silly. The Swift standard library opts for returning the index of the first item that matches the search criteria for precisely this reason. None of the other options make a whole lot of sense.
But putting it back into the context of your question, none of the tuples that you find with the value of "bananas" are going to be the exact (identical) instance of "bananas" that you passed in to your search function. No two value types are ever identical. They may be equal, but they are never identical.
One more note - mainly for clarification of what you are even trying to do. In your first attempt at writing this function, you appear to already know the index of the item you are searching for. You pass it in to the function as a parameter, right here:
// ----------vvvvv
func findInGenericIndexedList<T>(indexedList: [(index: Int, value: T)], element: (index: Int, value: T)) -> Int?
Just out of curiosity, is this a typo? Or do you actually know the index of the tuple that you are searching for? Because if you already know what it is, well... you don't need to search for it :)
Related
Could you explain why:
when I access an array value using array.first it's optional
when I access from an index value it is not?
Example:
var players = ["Alice", "Bob", "Cindy", "Dan"]
let firstPlayer = players.first
print(firstPlayer) // Optional("Alice")
let firstIndex = players[0]
print(firstIndex) // Alice
(The short answers to this question are great, and exactly what you need. I just wanted to go a bit deeper into the why and how this interacts with Swift Collections more generally and the underlying types. If you just want "how should I use this stuff?" read the accepted answer and ignore all this.)
Arrays follow the rules of all Collections. A Collection must implement the following subscript:
subscript(position: Self.Index) -> Self.Element { get }
So to be a Collection, Array's subscript must accept its Index and unconditionally return an Element. For many kinds of Collections, it is impossible to create an Index that does not exist, but Array uses Int as its Index, so it has to deal with the possibility that you pass an Index that is out of range. In that case, it is impossible to return an Element, and its only option is to fail to return at all. This generally takes the form of crashing the program since it's generally more useful than hanging the program, which is the other option.
(This hides a slight bit of type theory, which is that every function in Swift technically can return "crash," but we don't track that in the type system. It's possible to do that to distinguish between functions that can crash and ones that cannot, but Swift doesn't.)
This should naturally raise the question of why Dictionary doesn't crash when you subscript with a non-existant key. The reason is that Dictionary's Index is not its Key. It has a little-used subscript that provides conformance to Collection (little-used in top-level code, but very commonly used inside of stdlib):
subscript(position: Dictionary<Key, Value>.Index) -> Dictionary.Element { get }
Array could have done this as well, having an Array.Index type that was independent of Int, and making the Int subscript return an Optional. In Swift 1.0, I opened a radar to request exactly that. The team argued that this would make common uses of Array too difficult and that programmers coming to Swift were used to the idea that out-of-range was a programming error (crash). Dictionary, on the other hand, is common to access with non-existant keys, so the Key subscript should be Optional. Several years using Swift has convinced me they were right.
In general you shouldn't subscript arrays unless you got the index from the array (i.e. using index(where:)). But many Cocoa patterns make it very natural to subscript (cellForRow(at:) being the most famous). Still, in more pure Swift code, subscripting with arbitrary Ints often suggests a design problem.
Instead you should often use Collection methods like first and first(where:) which return Optionals and generally safer and clearer, and iterate over them using for-in loops rather than subscripts.
if you want to use subscript and you don't want to have a crash, you can add this extension to your code:
extension Collection {
subscript (safe index: Index) -> Iterator.Element? {
return indices.contains(index) ? self[index] : nil
}
}
and then use it:
let array = [0, 1, 2]
let second = array[safe:1] //Optional(1)
let fourth = array[safe:3] //nil instead of crash
The behavior of first and index subscription is different:
first is declared safely: If the array is empty it returns nil, otherwise the (optional) object.
index subscription is unsafe for legacy reasons: If the array is empty it throws an out-of-range exception otherwise it returns the (non-optional) object
This is because with first, if the Array is empty, the value will be nil. That is why it is an optional. If it is not empty, the first element will be returned.
However, with a subscript (or index value), your program will crash with an error
fatal error: Index out of range
If it is out of range (or is empty) and not return an optional. Else, it will return the element required.
There are default behavior of array property. Array is generic type of Element. When you try to access using first it return as optional.
public var first: Element? { get }
This is available in Array class.
I'm trying to write a "Restriction" of some data type, where a Restriction could be a list of Interest(enum), Experience(a range of years) or isVerified(boolean), etc. I have another class that has a property [Restriction]?.
I'm thinking about using enum but I'm not sure what's the correct/better way to construct this enum? Or maybe use struct? Any suggestions?
It's not clear from you question what "Restriction" means to you, but the way to decide is to say out loud what it means, and then use grammar to pick your types.
A struct is an "AND" type. For example:
struct Point {
let x: Double
let y: Double
}
A Point has an x coordinate AND a y coordinate. If a restriction has an interest and an experience level and a verification status, then that's a struct.
An enum is an "OR" type. For example:
enum Color {
case red
case blue
case green
}
A Color is red OR blue OR green. An enum case may also have associated data. For example:
enum Pattern {
case solid(Color)
case striped(Color, Color)
}
A Pattern is either solid with a single color OR it is striped with two colors. Notice the grammar again that helps us recognize our type: "x with y OR a with b."
Structs, classes, and tuples are all AND types, so you need some more rules to split them up. Tuples are basically anonymous structs, and they are mostly useful in Swift for short-lived, temporary values, like return values. If you find yourself wanting to create a typealias for a tuple, you probably wanted a struct instead. I find people overuse tuples (in Swift; they make more sense in other languages).
Structs are value types, while classes are reference types. The best way to understand the difference is that a value type is only its value. Any "instance" of the number 4 is identical to any other instance of the number 4. Nothing "owns" the number 4. You don't care where the number 4 came from. That's a value. The same is true for a Point. The Point (1,2) is entirely defined by the number 1 followed by the number 2. There is nothing else you can say about that Point. If your type is entirely defined by its properties, that is a good case for a struct. It should be easy to define equality between two values.
Classes are reference types. Reference types have identity. Two instances may have all the same property values, but be different "objects." When you want to ask "which one is this?" then you mean a class, not a struct. If you want to make sure two variables are "the same object" (rather than just "equal"), then you mean a class. There is a lot of pressure in Swift to use structs, but in practice, classes are extremely common, particularly in iOS development.
Thinking about what your type means, and saying it with clear language, will help you find the right types for your problem. If you're interested in a longer version of this, see Learning From Our Elders.
EDIT: Looking at your edits, I think what you're really building is a predicate. A predicate is just a function that returns yes or no given some value, and that's what I think a Restriction probably is. It looks like you want a collection of restrictions. I assume you want to then AND them all together.
A very nice way to build a predicate is with a closure. For example:
struct Element {
let interests: [String]
let experience: Int
}
struct Restriction {
let passes: (Element) -> Bool
init(hasInterest interest: String) {
passes = { $0.interests.contains(interest) }
}
init(hasAtLeastExperience years: Int) {
passes = { $0.experience >= years }
}
}
let element = Element(interests: ["fishing", "sewing"], experience: 5)
let restriction = Restriction(hasAtLeastExperience: 2)
restriction.passes(element)
With this you can easily build up groups of restrictions, apply them with AND or OR, etc.
Go with the Struct in your case because Structs are preferable if they are relatively small and copiable because copying is way safer than having multiple reference to the same instance as happens with classes. Your interest can be a list of the enum type Interest.
enum Interest {
}
struct Restriction {
let interest: [Interest]
let experience: Int
let isVerified: Bool
}
In Scala, the + (k -> v) operator on immutable.Map returns a new immutable.Map with the contents of the original, plus the new key/value pair. Similarly, in C#, ImmutableDictionary.add(k, v) returns a new, updated ImmutableDictionary.
In Swift, however, Dictionary appears only to have the mutating updateValue(v, forKey: k) function and the mutating [k:v] operator.
I thought maybe I could play some trick with flatten(), but no luck:
let updated = [original, [newKey: newValue]].flatten()
gets me
Cannot convert value of type '() -> FlattenCollection<[[String : AnyObject]]>'
to specified type '[String : AnyObject]'
How do I create a new, modified immutable Dictionary from the contents of an existing one?
Update: Based on this answer's note that Swift dictionaries are value types, and this answer's mutable version, I came up with the following extension operator, but I'm not excited about it -- it seems like there must be a cleaner out-of-the-box alternative.
func + <K, V>(left: [K:V], right: [K:V]) -> [K:V] {
var union = left
for (k, v) in right {
union[k] = v
}
return union
}
But maybe the fact (if I understand correctly) that the immutability of Swift dictionaries is a compiler check on let rather than a matter of different implementation classes means this is the best that can be done?
Update #2: As noted in Jules's answer, modifying immutable dictionaries that aren't specifically optimized to share state between copies (as Swift dictionaries aren't) presents performance problems. For my current use case (AttributedString attribute dictionaries, which tend to be fairly small) it may still simplify certain things enough to be worth doing, but until and unless Swift implements a shared-state immutable dictionary it's probably not a good idea in the general case -- which is a good reason not to have it as a built-in feature.
Unfortunately, this is a good question because the answer is "you can't". Not yet, anyway--others agree this should be added, because there's a Swift Evolution proposal for this (and some other missing Dictionary features). It's currently "awaiting review", so you may see a merged() method that's basically your + operator in a future version of Swift!
In the meantime, you can use your solution to append entire dictionaries, or for one value at a time:
extension Dictionary {
func appending(_ key: Key, _ value: Value) -> [Key: Value] {
var result = self
result[key] = value
return result
}
}
There's no built-in way to do this right now. You could write your own using an extension (below).
But keep in mind that this will likely copy the dictionary, because dictionaries are copy-on-write, and you're doing exactly that (making a copy, then mutating it). You can avoid all this by just using a mutable variable in the first place :-)
extension Dictionary {
func updatingValue(_ value: Value, forKey key: Key) -> [Key: Value] {
var result = self
result[key] = value
return result
}
}
let d1 = ["a": 1, "b": 2]
d1 // prints ["b": 2, "a": 1]
let d2 = d1.updatingValue(3, forKey: "c")
d1 // still prints ["b": 2, "a": 1]
d2 // prints ["b": 2, "a": 1, "c": 3]
The most straightforward thing to do is to copy to a variable, modify, then re-assign back to a constant:
var updatable = original
updatable[newKey] = newValue
let updated = updatable
Not pretty, obviously, but it could be wrapped into a function easily enough.
extension Dictionary {
func addingValue(_ value: Value, forKey key: Key) -> Dictionary<Key, Value> {
// Could add a guard here to enforce add not update, if needed
var updatable = self
updatable[key] = value
return updatable
}
}
let original = [1 : "One"]
let updated = original.addingValue("Two", forKey: 2)
I don't believe there's a solution other than roll-your-own.
But maybe the fact (if I understand correctly) that the immutability of Swift dictionaries is a compiler check on let
Right, mutability is specified on the storage, that is, the variable, not on the value.
Do not try to update an immutable dictionary unless it has been specifically designed for immutability.
Immutable dictionaries usually use a data structure (such as a red/black tree with immutable nodes than can be shared between instances or similar) that can generate a modified copy without needing to make copies of the entire content, but only a subset (i.e. they have O(log(n)) copy-and-modify operations) but most dictionaries that are designed for a mutable system and then used with an immutable interface do not, so have O(n) copy-and-modify operations. When your dictionary starts to get larger than a few hundred nodes, you'll really notice the performance difference.
The code example comes from the office swift document
let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
func backwards(s1: String, _ s2: String) -> Bool {
return s1 > s2
}
var reversed = names.sort(backwards)
backwards function had been used as the argument of the method sort(_:).
The function backwards returns boolean values. However, when I tried this names.sort(true) I've got an error from the compiler!
Why there are no errors in the example code?
Another question is, what's going on with s1 and s2 as the arguments? When did they get called? How the strings in names array get passed into them?
The function backwards returns boolean values, however, when I tried this names.sort(true)
The sort method being used is actually the sort(isOrderedBefore: (Element, Element) -> Bool) method which takes a comparison function as a parameter. The function has to take the particular set of parameters specified in the interface, i.e. a function that takes two Element parameters and returns a Bool.
As gnasher explained, you're getting an error because true is a value, not a function. You could write a function that returns true though, and that should work. Using Swift's trailing closure syntax, you could write:
names.sort() {return true}
That obviously wouldn't be very useful for actual sorting, but it shows how to make your example work.
what's going on with s1 and s2 as the arguments? When did they get called? How the strings in names array get passed into them?
That's the job of the sort method. It's an instance method belonging to ArraySlice, and it compares the elements in the slice two at a time to determine how they should be ordered. The actual comparison is done using the comparison method that you pass in, so that you can use the same sort method to sort your array using any sort order you can dream up. Try doing this:
let names = ["Harry", "David", "Susan", "Alice"]
let sortedNames = names.sort() {
print($0, $1)
return $0 < $1
}
And you should see a list of output lines as sort() calls your comparison method repeatedly.
"true" isn't a function comparing two strings. When you sort an array of strings, you need a function comparing two strings.
I'm trying to implement a basic multimap in Swift. Here's a relevant (non-functioning) snippet:
class Multimap<K: Hashable, V> {
var _dict = Dictionary<K, V[]>()
func put(key: K, value: V) {
if let existingValues = self._dict[key] {
existingValues += value
} else {
self._dict[key] = [value]
}
}
}
However, I'm getting an error on the existingValues += value line:
Could not find an overload for '+=' that accepts the supplied arguments
This seems to imply that the value type T[] is defined as an immutable array, but I can't find any way to explicitly declare it as mutable. Is this possible in Swift?
The problem is that you are defining existingValues as a constant with let. However, I would suggest changing the method to be:
func put(key: K, value: V) {
var values = [value]
if let existingValues = self._dict[key] {
values.extend(existingValues)
}
self._dict[key] = values
}
}
I feel that the intent of this is clearer as it doesn't require modifying the local array and reassigning later.
if var existingValues = self._dict[key] { //var, not let
existingValues += value;
// should set again.
self._dict[key] = existingValues
} else {
self._dict[key] = [value]
}
Assignment and Copy Behavior for Arrays
The assignment and copy behavior for Swift’s Array type is more complex than for its Dictionary type. Array provides C-like performance when you work with an array’s contents and copies an array’s contents only when copying is necessary.
If you assign an Array instance to a constant or variable, or pass an Array instance as an argument to a function or method call, the contents of the array are not copied at the point that the assignment or call takes place. Instead, both arrays share the same sequence of element values. When you modify an element value through one array, the result is observable through the other.
For arrays, copying only takes place when you perform an action that has the potential to modify the length of the array. This includes appending, inserting, or removing items, or using a ranged subscript to replace a range of items in the array. If and when array copying does take place, the copy behavior for an array’s contents is the same as for a dictionary’s keys and values, as described in Assignment and Copy Behavior for Dictionaries.
See: https://itunes.apple.com/us/book/the-swift-programming-language/id881256329?mt=11
Buckets is a data structures library for swift. It provides a multimap and allows subscript notation.
One easy way to implement a multi-map is to use a list of pairs (key, value) sorted by key, using binary search to find ranges of entries. This works best when you need to get a bunch of data, all at once. It doesn't work so well when you are constantly deleting and inserting elements.
See std::lower_bound from C++ for a binary search implementation which can be easily written in swift.