Swift "Where" Array Extensions

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 
{
// ...
}

Swift where Array Extensions


extension Array {
func filterWithId<T where T : Idable>(id : String) -> [T] {
...
}
}

defines a generic method filterWithId() where the generic
placeholder T is restricted to be Idable. But that definition introduces a local placeholder T
which is completely unrelated to the array element type T
(and hides that in the scope of the method).

So you have not specified that the array elements must conform
to Idable, and that is the reason why you cannot call
self.filter() { ... } with a closure which expects the elements
to be Idable.

As of Swift 2 / Xcode 7 beta 2, you can define extension methods on a generic type which are more restrictive on the template
(compare Array extension to remove object by value for a very similar issue):

extension Array where Element : Idable {

func filterWithId(id : String) -> [Element] {
return self.filter { (item) -> Bool in
return item.id == id
}
}
}

Alternatively, you can define a protocol extension method:

extension SequenceType where Generator.Element : Idable {

func filterWithId(id : String) -> [Generator.Element] {
return self.filter { (item) -> Bool in
return item.id == id
}
}
}

Then filterWithId() is available to all types conforming
to SequenceType (in particular to Array) if the sequence element
type conforms to Idable.

In Swift 3 this would be

extension Sequence where Iterator.Element : Idable {

func filterWithId(id : String) -> [Iterator.Element] {
return self.filter { (item) -> Bool in
return item.id == id
}
}
}

Array extension where Element is Optional and the the return type is Wrapped

I am not sure what you mean with Wrapped<Element> but since you need to return something why not use a closure for the return value, like this function to get the element at a specific index

extension Array  {
func value<T>(at index: Int, emptyAction: () -> T) -> T where Element == T? {
if let value = self[index] {
return value
}
return emptyAction()
}
}

Example

var test = [String?]()
test.append("ABC")
test.append("DEF")
test.append(nil)

for i in 0..<test.count {
print(test.value(at: i, emptyAction: { "<empty>" }))
}

Outputs

ABC   
DEF
<empty>

Applying superclass array extensions to arrays of subclass instances

Use : rather than == to mean "a subtype of":

class Superclass {

}

class Subclass : Superclass {

}

// here!
extension Array where Element: Superclass {
func f() {}
}

let a = [Subclass]()
a.f() // compiles!

Extension on Array where element is a generic struct in Swift

You will need to create a protocol with an associated type:

protocol MyGenericStructProtocol {
associatedtype GenericParameter
}

Let your struct adopt the protocol, either directly, or using an extension:

extension MyStruct: MyGenericStructProtocol {
typealias GenericParameter = T
}

Now you can reference the generic type inside your extension of Array:

extension Array where Element: MyGenericStructProtocol {
func doWork() -> [Element.GenericParameter] {
return []
}
}

Check out a fully working example on this GitHub gist

Array extension for finding index of custom type

You can extend Array and create a generic method to return the first index where the element is of an specific type:

extension Array {
func index<T>(with type: T.Type) -> Index? {
return index { $0 is T }
}
}

struct Fruit { }

let objects: [Any] = [1,2,Fruit(),"leedex"]
objects.index(with: Fruit.self) // 2

Swift Array extension with generic items

Try this:

import Foundation

protocol Section {
associatedtype InfoT: Equatable
associatedtype ItemsT: Equatable
var info: InfoT? { get }
var items: [ItemsT] { get }
}

extension Array where Element: Section {
// Just dummy example function:
func debugDummy() {
for section in self {
let info = section.info
print("section info: \(String(describing: info)).")
for item in section.items {
print("item: \(item).")
}
}
}
}

Extend array types using where clause in Swift

If you want to extend only array with specific type. You should extend _ArrayType protocol.

extension _ArrayType where Generator.Element == Int {

func doSomething() {
...
}
}

If you extend Array you can only make sure your element is conformed some protocol else. i.e:

extension Array where Element: Equatable {

func doSomething() {
...
}
}

Updated:
With Swift 3.1
https://github.com/apple/swift/blob/master/CHANGELOG.md

extension Array where Element == Int {

func doSomething() {
...
}
}

Swift: Extension on [ SomeType T ?] to produce [ T ?] possible?

I don't know if there is a simpler solution now, but you can use the same “trick” as in How can I write a function that will unwrap a generic property in swift assuming it is an optional type? and Creating an extension to filter nils from an Array in Swift, the idea goes back to this Apple Forum Thread.

First define a protocol to which all optionals conform:

protocol OptionalType {
associatedtype Wrapped
var asOptional: Wrapped? { get }
}

extension Optional : OptionalType {
var asOptional: Wrapped? {
return self
}
}

Now the desired extension can be defined as

extension Collection where Element: OptionalType, Element.Wrapped: SomeTypeProtocol {
var values: [Element.Wrapped.NumberType?] {
return self.map( { $0.asOptional?.value })
}
}

and that works as expected:

let arr = [SomeType(value: 123), nil, SomeType(value: 456)]
let v = arr.values

print(v) // [Optional(123), Optional(456)]
print(type(of: v)) // Array<Optional<Int>>


Related Topics



Leave a reply



Submit