Xcode Swift: extension of array: "can't invoke.. with argument list .. " [duplicate] - swift

I am trying to write a simple Array extension that provides a 'distinct' method. Here is what I have so far:
extension Array {
func distinct() -> T[] {
var rtn = T[]()
for x in self {
var containsItem = contains(rtn, x)
if !containsItem {
rtn.append(x)
}
}
return rtn
}
}
The problem is that the 'contains' statement fails as follows:
Could not find an overload for 'contains' that accepts the supplied arguments
I am pretty sure the type constraints are correct. Any ideas?

Swift 1.x
The elements in an array don't have to be Equatable, i.e. they don't have be comparable with ==.
That means you can't write that function for all possible Arrays. And Swift doesn't allow you to extend just a subset of Arrays.
That means you should write it as a separate function (and that's probably why contains isn't a method, either).
let array = ["a", "b", "c", "a"]
func distinct<T: Equatable>(array: [T]) -> [T] {
var rtn = [T]()
for x in array {
var containsItem = contains(rtn, x)
if !containsItem {
rtn.append(x)
}
}
return rtn
}
distinct(array) // ["a", "b", "c"]
Update for Swift 2/Xcode 7 (Beta)
Swift 2 supports restricting extensions to a subset of protocol implementations, so the following is now allowed:
let array = ["a", "b", "c", "a"]
extension SequenceType where Generator.Element: Comparable {
func distinct() -> [Generator.Element] {
var rtn: [Generator.Element] = []
for x in self {
if !rtn.contains(x) {
rtn.append(x)
}
}
return rtn
}
}
array.distinct() // ["a", "b", "c"]
Note how apple added SequenceType.contains using the same syntax.

Finally found out how to do it:
extension Array {
func contains<T : Equatable>(obj: T) -> Bool {
return self.filter({$0 as? T == obj}).count > 0
}
func distinct<T : Equatable>(_: T) -> T[] {
var rtn = T[]()
for x in self {
if !rtn.contains(x as T) {
rtn += x as T
}
}
return rtn
}
}
And usage/testing:
let a = [ 0, 1, 2, 3, 4, 5, 6, 1, 2, 3 ]
a.contains(0)
a.contains(99)
a.distinct(0)
Unfortunately, I can't figure out a way to do it without having to specify an argument which is subsequently ignored. The only reason it's there is to invoke the correct form of distinct. The major advantage of this approach for distinct seems to be that it's not dumping a common term like distinct into the global namespace. For the contains case it does seem more natural.

Another solution is to use the find(Array:[T], obj:T) function. It will return an optional Int, so what you could do is
if let foundResult = find(arr, obj) as Int
{
//obj is contained in arr
} else
{
//obj is not contained in arr.
}

As of Swift 2, this can be achieved with a protocol extension method,
e.g. on all types conforming to SequenceType where the sequence
elements conform to Equatable:
extension SequenceType where Generator.Element : Equatable {
func distinct() -> [Generator.Element] {
var rtn : [Generator.Element] = []
for elem in self {
if !rtn.contains(elem) {
rtn.append(elem)
}
}
return rtn
}
}
Example:
let items = [1, 2, 3, 2, 3, 4]
let unique = items.distinct()
print(unique) // [1, 2, 3, 4]
If the elements are further restricted to be Hashable then you
can take advantage of the Set type:
extension SequenceType where Generator.Element : Hashable {
func distinct() -> [Generator.Element] {
return Array(Set(self))
}
}

Related

How can I pass in any function as a parameter?

I'm trying to make an extension to Array, see below
extension Array {
func mapThenUnique<T: Comparable>(f: (Element) -> T) -> Array<T> {
var mapped: Array<T> = Array(self.filter( f(self) ))
/* Three Errors /\
1) Cannot assign value of type '[Element]' to type 'Array<T>'
2) Cannot convert value of type 'Array<Element>' to expected argument type 'Element'
3) Cannot convert value of type 'T' to expected argument type '(Element) throws -> Bool' */
var noDups: Array<T> = []
for element in mapped {
if (!noDups.contains(where: element)) { noDups.append(element) }
// Error - Cannot convert value of type 'T' to expected argument type '(T) throws -> Bool'
}
return noDups
}
}
I know the noDups array has to be of type 'T' because that is the correct return type, see below for an example of what mapThenUnique does:
["abc", "Hi", "AbC"].mapThenUnique { $0.lowercased() } -> ["abc", "hi"]
[2, 9, -9, 3].mapThenUnique { Int($0) * $0 } -> [4, 9, 81]
// notice that there are no duplicates in the array
But I'm not sure why I am getting these error messages. And what does '(Element) throws -> Bool' mean? Any help will be greatly appreciated!
Edit:
My now awake brain realizes that it should be map instead of filter, thanks #Sulthan.
extension Array {
func mapThenUnique<T: Comparable>(f: (Element) -> T) -> Array<T> {
var mapped: Array<T> = self.map{ f($0) }
var noDups: Array<T> = []
for element in filtered {
if (!noDups.contains(where: element)) { noDups.append(element) }
// Error - Cannot convert value of type 'T' to expected argument type '(T) throws -> Bool'
}
noDups.sort()
// this works for the numerical test cases but not for ["abc", "Hi", "AbC"] which returns ["abc", "hi"], idk why it does
return noDups
}
}
I'm still trying to figure out what the error message in the for loop means. Oh, this is for a HW assignment.
If you use a Set and make it Hashable instead of Comparable, it's fairly straightforward
extension Array {
func mapThenUnique<T: Hashable>(f: (Element) -> T) -> [T] {
var seen = Set<T>()
return map { f($0) }.filter { seen.insert($0).inserted }
}
}
["abc", "Hi", "AbC"].mapThenUnique { $0.lowercased() } // ["abc", "hi"]
[2, 9, -9, 3].mapThenUnique { Int($0) * $0 } // [4, 81, 9]
Or if you don't care about the original order
Set(["abc", "Hi", "AbC"].map { $0.lowercased() }) // ["abc", "hi"] or ["hi", "abc"]
Set([2, 9, -9, 3].map { Int($0) * $0 }) // Some random order of [4, 81, 9]
Also a more "correct" way to do this in Swift would be to create the extension on Collection
extension Collection where Element: Hashable {
func mapThenUnique(f: (Element) -> Element) -> [Element] {
var seen = Set<Element>()
return map { f($0) }.filter { seen.insert($0).inserted }
}
}
Although I consider it "bad form" to have a function that does two things, so my personal preference would be
extension Collection where Element: Hashable {
func unique() -> [Element] {
var seen = Set<Element>()
return filter { seen.insert($0).inserted }
}
}
["abc", "Hi", "AbC"].map { $0.lowercased() }.unique()
(Again, assuming you want to keep the order. Otherwise, just use a Set!)

Does Swift have a function similar to numpy.diff that calculates the difference between adjacent elements of an array

I'm trying to convert some Python code to Swift and wondering if there is an existing function to calculate the difference between successive elements in a Swift array. For example:
diff([1,3,5,6,10]) would return [2,2,1,4]
No, but it could be very easily implemented:
let a = [1, 3, 5, 6, 10]
zip(a.dropFirst(), a).map(-) // => [2, 2, 1, 4]
It's simple enough that it's probably not worth wrapping into a function, but if you insist:
extension Collection where Element: Numeric {
func diff() -> [Element] {
return zip(self.dropFirst(), self).map(-)
}
}
[1, 3, 5, 6, 10].diff() // => [2, 2, 1, 4]
If you need the result to be lazily evaluated, you can do this:
extension Collection where Element: Numeric {
func diff() -> AnyCollection<Element> {
return AnyCollection(zip(self.dropFirst(), self).lazy.map(-))
}
}
You can use reduce(into:) combined with dropfirst to achieve what you want:
extension Collection where Element: SignedNumeric {
func diff() -> [Element] {
guard var last = first else { return [] }
return dropFirst().reduce(into: []) {
$0.append($1 - last)
last = $1
}
}
}
Another option is to use map and defer:
extension Collection where Element: SignedNumeric {
func diff() -> [Element] {
guard var last = first else { return [] }
return dropFirst().map { element in
defer { last = element }
return element - last
}
}
}
let arr = [1,3,5,6,10]
print(arr.diff()) // "[2, 2, 1, 4]\n"
There's no built in function for this, but you can easily implement it recursively. Thanks for the HeadTail extension for #Alexander.
extension Array {
func headTail<ReturnType>(_ closure: (Element?, [Element]) -> ReturnType) -> ReturnType {
return closure(self.first, Array(self.dropFirst()))
}
}
extension Array where Element == Int {
func diff() -> [Int] {
return self.headTail { head, tail in
guard let head = head, let next = tail.first else { return [] } //base case, empty list
return [next - head] + tail.diff()
}
}
}

Is it possible to have a range as a key in a Swift Dictionary?

For simplification. Lets say i have some unique values -> the numbers from 1 to 10
Now I want 1-5 map to the value "first" and I want 6-10 map to the value "second"
Is there a way I can create or extend a dictionary to work like the following?
let dict: [Range<Int> : String]
The goal is to have the following results:
print(dict[1]) // prints first
print(dict[2]) // prints first
print(dict[3]) // prints first
print(dict[7]) // prints second
print(dict[8]) // prints second
print(dict[9]) // prints second
The way I am currently doing it is to simply have the multiple keys map to the same value. But my dictionary can have sometimes 60k values. So I am wondering if a range can work.
I know I can make the value into a class instead of a struct so that multiple keys can map to the same class object, but I was wondering if simply creating a Dictionary that worked like above was possible?
If you insist on using Dictionary, you have to wait until Swift 3.1 (currently in beta):
extension CountableClosedRange : Hashable {
public var hashValue: Int {
return "\(lowerBound) to \(upperBound)".hashValue
}
}
// This feature is called concrete-type extension and requires Swift 3.1
extension Dictionary where Key == CountableClosedRange<Int> {
subscript(rawValue rawValue: Int) -> Value? {
for k in self.keys {
if k ~= rawValue {
return self[k]
}
}
return nil
}
}
let dict : [CountableClosedRange<Int>: String] = [
1...5: "first",
6...10: "second"
]
print(dict[rawValue: 1])
print(dict[rawValue: 2])
print(dict[rawValue: 3])
print(dict[rawValue: 7])
print(dict[rawValue: 8])
print(dict[rawValue: 9])
However, it's a lot clearer if you implement your own data model:
struct MyRange {
var ranges = [CountableClosedRange<Int>]()
var descriptions = [String]()
mutating func append(range: CountableClosedRange<Int>, description: String) {
// You can check for overlapping range here if you want
self.ranges.append(range)
self.descriptions.append(description)
}
subscript(value: Int) -> String? {
for (i, range) in self.ranges.enumerated() {
if range ~= value {
return descriptions[i]
}
}
return nil
}
}
var range = MyRange()
range.append(range: 1...5, description: "one")
range.append(range: 6...10, description: "second")
print(range[1])
print(range[2])
print(range[6])
print(range[7])
print(range[100])
This is in Swift 3.0, it may not be as nice as Code Different's answer though.
class MyRange: Hashable, Equatable {
public var hashValue: Int {
get {
return (self.range.lowerBound + self.range.upperBound).hashValue
}
}
var range: Range<Int>!
public static func ==(_ lhs: MyRange, _ rhs: MyRange) -> Bool {
return lhs.range == rhs.range
}
init(range: Range<Int>) {
self.range = range
}
}
extension Dictionary where Key: MyRange, Value: ExpressibleByStringLiteral {
internal subscript(index: Int) -> [String] {
return self.filter({$0.key.range.contains(index)}).map({$0.value as! String})
}
}
Now, you can make your dictionary like so:
var dict = Dictionary<MyRange, String>()
dict[MyRange(range: 0..<5)] = "first"
dict[MyRange(range: 5..<10)] = "second"
Getting values works with Integers and Ranges:
print(dict[1]) // ["first"]
print(dict[5]) // ["second"]
print(dict[11]) // []
print(dict[MyRange(range: 0..<5)]) // "first"
print(dict[MyRange(range: 0..<6)]) // nil
The dictionary should look like this:
print(dict)
// [MyRange: "first", MyRange: "second"]

Swift function to find first element of collection matching a predicate?

If xs is a collection and pred is a closure that returns a Bool, is there a built-in function that does the following?
xs.filter(pred).first
This gets the first element of a collection matching the predict, or nil if there is no match. Not interested in the index, but the element itself.
No there isn't, but you can write one yourself like this:
extension SequenceType {
func first(#noescape pred: Generator.Element throws -> Bool) rethrows -> Generator.Element? {
return try filter(pred).first
}
}
EDIT: This version isn't optimal, since the filter creates a whole new array, even though only the first element would be needed. As noted by Martin R, lazy.filter also doesn't work for. This would be necessary to make it work with lazy:
extension CollectionType {
func first(pred: Generator.Element -> Bool) -> Generator.Element? {
return lazy.filter(pred).first
}
}
Because:
#noescape can't be used because #noescape means that the closure cannot escape the current function, which would be possible when passing it to the lazy filter (doesn't evaluate elements until it is asked to -> has to escape the predicate)
throws can't be used because the filter is lazy -> errors wouldn't be thrown immediately, but rather when it is used the first time which would be when calling first, but first can't be throwing because it's a property. There are some discussions on making getters (and subscripts) throwing in future versions of Swift.
CollectionType has to be used, because only LazyCollectionType has the first property.
So to really make it lazy and have all the #noescape, throws and SequenceType, you'd have to use an imperative approach:
extension SequenceType {
func first(#noescape pred: Generator.Element throws -> Bool) rethrows -> Generator.Element? {
for elem in self where try pred(elem) {
return elem
}
return nil
}
}
In the simplest case, what you want may look like this:
let array = [18, 12, 35, 11, 12, 44]
var first: Int?
for element in array where element == 12 {
first = element
break
}
print(first) // prints: Optional(12)
If you really need to set a predicate closure, you can use the following pattern:
let array = [18, 12, 35, 11, 12, 44]
var first: Int?
let predicateClosure = { (value: Int) -> Bool in
return value == 12
}
for element in array where predicateClosure(element) {
first = element
break
}
print(first) // prints: Optional(12)
If you need to repeat these operations, you can refactor your code by using a SequenceType protocol extension:
extension SequenceType where Generator.Element == Int {
func getFirstWithPredicate(predicate: Int -> Bool) -> Int? {
for element in self where predicate(element) {
return element
}
return nil
}
}
let array = [18, 12, 35, 11, 12, 44]
let predicateClosure: Int -> Bool = {
return $0 == 12
}
let first = array.getFirstWithPredicate(predicateClosure)
print(first) // prints: Optional(12)
Note that you don't need your predicate closure parameter to escape your getFirstWithPredicate(_:) method here, so you can add the #noescape attribute before it (see Nonescaping Closures for more details):
extension SequenceType where Generator.Element == Int {
func getFirstWithPredicate(#noescape predicate: Int -> Bool) -> Int? {
for element in self where predicate(element) {
return element
}
return nil
}
}
let array = [18, 12, 35, 11, 12, 44]
let predicateClosure = { $0 == 12 }
let first = array.getFirstWithPredicate(predicateClosure)
print(first) // prints: Optional(12)
If you want the previous code to work for any type of sequence, you can remove the Int constraint and redeclare your getFirstWithPredicate(_:) method like in the following example:
extension SequenceType {
func getFirstWithPredicate(#noescape predicate: Generator.Element -> Bool) -> Generator.Element? {
for element in self where predicate(element) {
return element
}
return nil
}
}
let intArray = [18, 12, 35, 11, 12, 44]
let firstInt = intArray.getFirstWithPredicate { $0 == 12 }
print(firstInt) // prints: Optional(12)
let stringArray = ["Car", "Boat", "Plane", "Boat", "Bike"]
let firstString = stringArray.getFirstWithPredicate { $0 == "Boat" }
print(firstString) // prints: Optional("Boat")
If you're using a CollectionType protocol conforming object (for example, an Array), you can easily get the last element that matches your predicate with the same getFirstWithPredicate(_:) declaration by using reverse():
extension SequenceType {
func getFirstWithPredicate(#noescape predicate: Generator.Element -> Bool) -> Generator.Element? {
for element in self where predicate(element) {
return element
}
return nil
}
}
struct Toy {
let name: String
let price: Int
}
let array = [
Toy(name: "Ball", price: 20),
Toy(name: "Car", price: 12),
Toy(name: "Plane", price: 35),
Toy(name: "Boat", price: 12),
]
let lastToyWithMatchingPrice = array.reverse().getFirstWithPredicate { $0.price == 12 }
print(lastToyWithMatchingPrice) // prints: Optional(Toy(name: "Boat", price: 12))

How can I make a extension for array of specific type in Swift

for say I have:
struct S {
var num = 0
}
I wanna implement a function allEqual() as extension for Array<S>, so I could do thing like
var s1 = S()
var s2 = S()
var s3 = S()
var equality = [s1,s2,s3].allEqual()
for say the specific type is S
extension CollectionType where Generator.Element == S {
}
CollectionType Protocol
In the latest Swift 3.1. You can do same-type constraints on the concrete type extension. So in your case, you can do:
extension Array where Element == S {
func allEqual() -> Bool {
...
}
}
I created an extension that works lazily for any SequenceType whose Elements are Equatable. In Swift, it is good practice to make your code work on exactly what it can work on: To be able to get whether all elements are equal it has to be a sequence of equatable values. Here is the code:
extension SequenceType where Generator.Element : Equatable {
var allEqual : Bool {
var gen = generate() // Generate the sequence for the first element
return gen.next().map { fst in // Get first element and map it (when existing)
!contains { fst != $0 } // To whether self doesn't contain any elements unequal to first
} ?? true // When first is nil, return true
}
}
Or you can also do it more iterative (which is basically the same I think is faster?):
extension SequenceType where Generator.Element : Equatable {
var allEqual : Bool {
var gen = generate()
let first = gen.next()
return !contains { $0 != first }
}
}
Also you should make your struct conform to the Equatable protocol like this:
func ==(lhs: S, rhs: S) -> Bool {
return lhs.x == rhs.x
}
because every value type should be equatable and obviously it makes total sense in your code to do this.
Here is some test code:
[S(x: 3), S(x: 3), S(x: 3)].allEqual // true
[S(x: 5), S(x: 3), S(x: 3)].allEqual // false
[S(x: 5), S(x: 5)].allEqual // true
[S(x: 0)].allEqual // true
[S]().allEqual // true
Note that it is lazy, which means that it will return false as soon as there is an element which isn't equal to the first one, so if you have something like this:
let longList = [S(x: 5)] + [S](count: 100000, repeatedValue: S(x: 4))
// [{x 5}, {x 4}, {x 4}, {x 4}, {x 4}, {x 4}, {x 4}, ...
longList.allEqual // false
will return at the second element, because there is an equality already
EDIT: My previous function was unnecessarily complicated. The new one is still lazy just shorter