Comparing objects in an Array extension causing error in Swift
You can always create an extension that uses NSArray's indexOfObject, e.g:
extension Array {
func indexOfObject(object:AnyObject) -> Int? {
return (self as NSArray).indexOfObject(object)
}
}
You can specify that your array items can be compared with the <T : Equatable>
constraint, then you can cast your object into T
and compare them, e.g:
extension Array {
func indexOfObject<T : Equatable>(o:T) -> Int? {
if self.count > 0 {
for (idx, objectToCompare) in enumerate(self) {
let to = objectToCompare as T
if o == to {
return idx
}
}
}
return nil
}
}
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.
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)
Compare two objects in Swift
You want Comparable, not Equatable. Equatable only has ==
.
Swift extension of ArrayMutableCollection won't allow reverse()
First of all, the extension should be declared like this:
extension Array where Element : MutableCollection {
You want to check that Element
adheres to the protocol MutableCollection
, not that it is a MutableCollection
However, then I'm not able to call the reverse
method on the subscript
for some reason. The best I've been able to do is this:
extension Array where Element : MutableCollection {
mutating func mirror() {
for index in self.indices {
self[index] = self[index].reversed() as! Element
}
}
}
Which works as you need it to work although the forced cast is very ugly and I dislike doing it. I suppose I should test the cast to be certain but I can't see any case where calling reversed()
would result in a collection that couldn't be cast back to Element
.
Edit:
I figured out the issue. The reverse()
method is only valid on MutableCollection
when it is also a BidirectionalCollection
. This code now works correctly:
extension MutableCollection where
Iterator.Element : MutableCollection &
BidirectionalCollection,
Indices.Iterator.Element == Index {
mutating func mirror() {
for index in self.indices {
self[index].reverse()
}
}
}
Now the code should work for all MutableCollection
whose elements are both a MutableCollection
and BidirectionalCollection
- such as [Array<Int>]
or even [ArraySlice<Int>]
You can see the full code for reverse()
in Swift 3.1 here:
Reverse.swift
extension MutableCollection where Self : BidirectionalCollection
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
{
// ...
}
Provide a catch if index is out of range (Swift 5)
You can use indices
to check if an array contains an index prior to accessing it:
guard myArray.indices.contains(1) else { return }
let value = myArray[1]
Apple documentation: indices
Related Topics
Datefromstring() Returns Incorrect Date
Swiftui - Navigation View Opening with Back Button and Half Grey Screen/Weird Behavior
Avaudioplayer.Play() Works But Avaudioplayernode.Play() Fails
Swift How to Sort Dict Keys by Byte Value and Not Alphabetically
Label Showing Top of Screen Instead of Being on the Inputaccessoryview
Need Clarification for Swift Type Properties
Getting the Count of an Optional Array as a String, or Nil
Error "{ Expected After If Statement"
Uitextview Linktextattributes Font Attribute Not Applied to Nsattributedstring
Swift: Can't Edit Properties of Custom Table Cell Programmatically
Swiftui Tabview Gives an Error Message During Add/Delete the Element of Coredata
Replace Multiple Words from a String Based on the Values in an Array
Value of Optional Type 'Nsurl' Not Unwrapped; Did You Mean to Use '!' or ''
Getting Wrong Date from Dateformat