Unable to use contains within a Swift Array extension
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.
How can I use contains function in Array extension in Swift?
That contains
overload only works when your elements are Equatable
.
extension Sequence where Element: Equatable {
func addCheck(value: Element) {
print(
contains(value)
? "Element exists!"
: "Element does not exist!"
)
}
}
Swift contains extension for Array
you don't actually need to write an extension, you can use the global func contains
from the Swift library:
contains([1,2,3], 1)
How can I extend typed Arrays in Swift?
For extending typed arrays with classes, the below works for me (Swift 2.2). For example, sorting a typed array:
class HighScoreEntry {
let score:Int
}
extension Array where Element == HighScoreEntry {
func sort() -> [HighScoreEntry] {
return sort { $0.score < $1.score }
}
}
Trying to do this with a struct or typealias will give an error:
Type 'Element' constrained to a non-protocol type 'HighScoreEntry'
Update:
To extend typed arrays with non-classes use the following approach:
typealias HighScoreEntry = (Int)
extension SequenceType where Generator.Element == HighScoreEntry {
func sort() -> [HighScoreEntry] {
return sort { $0 < $1 }
}
}
In Swift 3 some types have been renamed:
extension Sequence where Iterator.Element == HighScoreEntry
{
// ...
}
Array containsObject() extension
That means there is no need to use conditional cast. Remove the if let and change as?
to as
extension Array {
func containsObject(_ object: Any) -> Bool {
for obj in self {
if obj as AnyObject === object as AnyObject {
return true
}
}
return false
}
}
Or simply:
extension Array {
func containsObject(_ object: Any) -> Bool {
return contains(where: {$0 as AnyObject === object as AnyObject})
}
}
How can I make a extension for array of specific type in Swift
for say the specific type is S
extension CollectionType where Generator.Element == S {
}
CollectionType Protocol
Extension for Array where Element is Optional
This is kind of tricky but you can create an AnyOptional protocol that requires an associatedtype (Wrapped) and a computed property to return the optional type. Then you can return the element unwrapped if the index is valid otherwise return nil.
protocol AnyOptional {
associatedtype Wrapped
var optional: Optional<Wrapped> { get }
}
extension Optional: AnyOptional {
var optional: Optional<Wrapped> { self }
}
extension Collection {
subscript(safe index: Index) -> Element? {
indices.contains(index) ? self[index] : nil
}
}
extension Collection {
subscript(safe index: Index) -> Element.Wrapped? where Element: AnyOptional {
indices.contains(index) ? self[index].optional ?? nil : nil
}
}
var myArray: [String?] = ["2", "banana", nil, "31"]
var myStringArray: [String] = ["2", "3"]
let item = myArray[safe: 1] // item is String?
let strItem = myStringArray[safe: 99] // strItem is String?
How to extend an Array Double ?
If you want to map your array elements and need also its index position you should use the method enumerated()
. I would also extend BidirectionalCollection
instead of RandomAccessCollection
and as already mentioned in comments by @Hamish using enumerated you can omit the Index == Int
constraint.
protocol BidirectionalCollection : BidirectionalIndexable, Collection
Description: A collection that supports backward as well as forward
traversal. Bidirectional collections offer traversal backward from any
valid index, not including a collection’s startIndex. Bidirectional
collections can therefore offer additional operations, such as a last
property that provides efficient access to the last element and a
reversed() method that presents the elements in reverse order. In
addition, bidirectional collections have more efficient
implementations of some sequence and collection methods, such as
suffix(_:).
extension BidirectionalCollection where Iterator.Element == Double, IndexDistance == Int {
public func applyWindowing() -> [Iterator.Element] {
return enumerated().map{ $0.element * windowingFunc(index: $0.offset, N: count)}
}
}
Related Topics
Nsdateformatter Return Wrong Date + Swift
Remove Element from Collection During Iteration with Foreach
Firebase Email Verification at Signup
How to Check If a Property Value Exists in Array of Objects in Swift
How to Draw Text in PDF Context in Swift
How to Detect a Swiftui Touchdown Event with No Movement or Duration
What Causes 'Constant Captured by a Closure Before Being Initialized' Error
Firebase Query Ordering Not Working Properly
Best Way to Make Amazon Aws Dynamodb Queries Using Swift
Alamofire - Nsurlcache Is Not Working
Why Are Doubles Printed Differently in Dictionaries
Why Non Optional Any Can Hold Nil
How to Get Directory Size with Swift on Os X
How to Do If Pattern Matching with Multiple Cases