Any way to iterate a tuple in swift? - swift

I am curious how to do a for loop with a tuple in swift.
I know that to access each member you can use dot notation using the index number
var tupleList = ("A",2.9,3,8,5,6,7,8,9)
for each in tupleList {
println(each)
}
//Error: Type does not conform to protocol sequence

Yes, you can!
func iterate<C,R>(t:C, block:(String,Any)->R) {
let mirror = reflect(t)
for i in 0..<mirror.count {
block(mirror[i].0, mirror[i].1.value)
}
}
And voila!
let tuple = ((false, true), 42, 42.195, "42.195km")
iterate(tuple) { println("\($0) => \($1)") }
iterate(tuple.0){ println("\($0) => \($1)")}
iterate(tuple.0.0) { println("\($0) => \($1)")} // no-op
Note the last one is not a tuple so nothing happens (though it is a 1-tuple or "Single" which content can be accessed .0, reflect(it).count is 0).
What's interesting is that iterate() can iterate even other types of collection.
iterate([0,1]) { println("\($0) => \($1)") }
iterate(["zero":0,"one":1]) { println("\($0) => \($1)") }
And that collection includes class and struct!
struct Point { var x = 0.0, y = 0.0 }
class Rect { var tl = Point(), br = Point() }
iterate(Point()) { println("\($0) => \($1)") }
iterate(Rect()) { println("\($0) => \($1)") }
Caveat: the value passed as the 2nd argument of the block is type Any. You have to cast it back to the values with original type.

You can using reflection Swift 5
Try this in a Playground:
let tuple = (1, 2, "3")
let tupleMirror = Mirror(reflecting: tuple)
let tupleElements = tupleMirror.children.map({ $0.value })
tupleElements
Output:

Swift does not currently support iterating over tuples.
The biggest reasons are:
There is no way at runtime to determine the number of elements in a tuple
There is no way to access an element at a specific index except for the compile time accessors like tupleList.0. You would really want a subscript tupleList[0] but that is not provided to us
Frankly, I can't see a reason that you would use a tuple instead of an Array if you want to iterate over it.
It doesn't make sense to iterate over a tuple because:
Tuples always have a fixed length and each element has a fixed type
You can name each tuple member with a name you can use to access it later
Arrays are well made to iterate over:
Arbitrary length
Can store multiple types using a common superclass or AnyObject
Can be declared as a literal in a similar fashion to tuples: var list = ["A",2.9,3,8,5,6,7,8,9]

#dankogai's excellent solution, updated for Swift 3.0:
func iterate<Tuple>(_ tuple:Tuple, body:(_ label:String?,_ value:Any)->Void) {
for child in Mirror(reflecting: tuple).children {
body(child.label, child.value)
}
}
Usage remains identical to #dankogai's examples (beyond Swift 2's println()→print() rename).
Note that the label is now of type String? when it was formerly String, to match the type change from Swift 1's MirrorType.subscript(…).0 to Swift 3's Mirror.Child.label.  However, for labelless tuples the label arg comes back as ".0", ".1", ".2", etc.— it's only nil for some other types.
Also, I took the liberty of renaming types & args to better match Swift 3's solidified naming standards, and changing the closure return type to Void.
Sidenote: I noticed somebody downvoted me here— I can't imagine why, other than the (fair) argument that building app functionality around reflection in Swift is hacking the type system, and is likely to lead to crappy code throughout (Swift's tuples shouldn't be considered an abstract data type, but rather a small collection of variables, akin to method args).  As a counter-argument, I originally ended up porting this to Swift 3 in project because I needed it— for better descriptions and debugDescriptions.  Because sane debug output will saves you hours and hours of frustration. ;-)  Additionally, this could be really useful for unit tests… because tests are ultimately most interested in “did the result of this operation match what we expect?”

Details
Xcode 11.2.1 (11B500), Swift 5.1
Base Solution
struct Tuple<T> {
let original: T
private let array: [Mirror.Child]
init(_ value: T) {
self.original = value
array = Array(Mirror(reflecting: original).children)
}
func forEach(closure: (Mirror.Child) -> Void) { array.forEach { closure($0) } }
func getOnlyValues<T: Any>() -> [T] { array.compactMap { $0.value as? T } }
func getAllValues() -> [Any] { array.compactMap { $0.value } }
}
Usage on base solution
let num: Int? = 3
let str: String? = nil
let x = (1, "stew", str, 5.4, 2, num)
let tuple = Tuple(x)
tuple.forEach { print("\($0)") }
print("\(tuple.getAllValues())") // [1, "stew", nil, 5.4, 2, Optional(3)]
print("\(tuple.getOnlyValues() as [Int])") // [1, 2, 3]
More sugar
func valuesFrom<V>(tuple: V) -> [Any] { return Tuple(tuple).getAllValues() }
func onlyValuesFrom<T,V>(tuple: V) -> [T] { return Tuple(tuple).getOnlyValues() as [T] }
print(valuesFrom(tuple: x)) // [1, "stew", nil, 5.4, 2, Optional(3)]
print(onlyValuesFrom(tuple: x) as [Int]) // [1, 2, 3]

No, you can't. The reason is that tuple items are not all required to have the same type, so you would not be able to know what type each should have.

Related

How to count the number of dimensions in Swift array [duplicate]

Suppose I have some function that I want to populate my data structure using a multi-dimensional array (e.g. a Tensor class):
class Tensor {
init<A>(array:A) { /* ... */ }
}
while I could add in a shape parameter, I would prefer to automatically calculate the dimensions from the array itself. If you know apriori the dimensions, it's trivial to read it off:
let d1 = array.count
let d2 = array[0].count
However, it's less clear how to do it for an N-dimensional array. I was thinking there might be a way to do it by extending the Array class:
extension Int {
func numberOfDims() -> Int {
return 0
}
}
extension Array {
func numberOfDims() -> Int {
return 1+Element.self.numberOfDims()
}
}
Unfortunately, this won't (rightfully so) compile, as numberOfDims isn't defined for most types. However, I'm don't see any way of constraining Element, as Arrays-of-Arrays make things complicated.
I was hoping someone else might have some insight into how to solve this problem (or explain why this is impossible).
If you're looking to get the depth of a nested array (Swift's standard library doesn't technically provide you with multi-dimensional arrays, only jagged arrays) – then, as shown in this Q&A, you can use a 'dummy protocol' and typecasting.
protocol _Array {
var nestingDepth: Int { get }
}
extension Array : _Array {
var nestingDepth: Int {
return 1 + ((first as? _Array)?.nestingDepth ?? 0)
}
}
let a = [1, 2, 3]
print(a.nestingDepth) // 1
let b = [[1], [2, 3], [4]]
print(b.nestingDepth) // 2
let c = [[[1], [2]], [[3]], [[4], [5]]]
print(c.nestingDepth) // 3
(I believe this approach would've still worked when you had originally posted the question)
In Swift 3, this can also be achieved without a dummy protocol, but instead by casting to [Any]. However, as noted in the linked Q&A, this is inefficient as it requires traversing the entire array in order to box each element in an existential container.
Also note that this implementation assumes that you're calling it on a homogenous nested array. As Paul notes, it won't give a correct answer for [[[1], 2], 3].
If this needs to be accounted for, you could write a recursive method which will iterate through each of the nested arrays and returning the minimum depth of the nesting.
protocol _Array {
func _nestingDepth(minimumDepth: Int?, currentDepth: Int) -> Int
}
extension Array : _Array {
func _nestingDepth(minimumDepth: Int?, currentDepth: Int) -> Int {
// for an empty array, the minimum depth is the current depth, as we know
// that _nestingDepth is called where currentDepth <= minimumDepth.
guard !isEmpty else { return currentDepth }
var minimumDepth = minimumDepth
for element in self {
// if current depth has exceeded minimum depth, then return the minimum.
// this allows for the short-circuiting of the function.
if let minimumDepth = minimumDepth, currentDepth >= minimumDepth {
return minimumDepth
}
// if element isn't an array, then return the current depth as the new minimum,
// given that currentDepth < minimumDepth.
guard let element = element as? _Array else { return currentDepth }
// get the new minimum depth from the next nesting,
// and incrementing the current depth.
minimumDepth = element._nestingDepth(minimumDepth: minimumDepth,
currentDepth: currentDepth + 1)
}
// the force unwrap is safe, as we know array is non-empty, therefore minimumDepth
// has been assigned at least once.
return minimumDepth!
}
var nestingDepth: Int {
return _nestingDepth(minimumDepth: nil, currentDepth: 1)
}
}
let a = [1, 2, 3]
print(a.nestingDepth) // 1
let b = [[1], [2], [3]]
print(b.nestingDepth) // 2
let c = [[[1], [2]], [[3]], [[5], [6]]]
print(c.nestingDepth) // 3
let d: [Any] = [ [[1], [2], [[3]] ], [[4]], [5] ]
print(d.nestingDepth) // 2 (the minimum depth is at element [5])
Great question that sent me off on a goose chase!
To be clear: I’m talking below about the approach of using the outermost array’s generic type parameter to compute the number of dimensions. As Tyrelidrel shows, you can recursively examine the runtime type of the first element — although this approach gives nonsensical answers for heterogenous arrays like [[[1], 2], 3].
Type-based dispatch can’t work
As you note, your code as written doesn’t work because numberOfDims is not defined for all types. But is there a workaround? Does this direction lead somewhere?
No, it’s a dead end. The reason is that extension methods are statically dispatched for non-class types, as the following snippet demonstrates:
extension CollectionType {
func identify() {
print("I am a collection of some kind")
}
func greetAndIdentify() {
print("Hello!")
identify()
}
}
extension Array {
func identify() {
print("I am an array")
}
}
[1,2,3].identify() // prints "I am an array"
[1,2,3].greetAndIdentify() // prints "Hello!" and "I am a collection of some kind"
Even if Swift allowed you to extend Any (and it doesn’t), Element.self.numberOfDims() would always call the Any implementation of numberOfDims() even if the runtime type of Element.self were an Array.
This crushing static dispatch limitation means that even this promising-looking approach fails (it compiles, but always returns 1):
extension CollectionType {
var numberOfDims: Int {
return self.dynamicType.numberOfDims
}
static var numberOfDims: Int {
return 1
}
}
extension CollectionType where Generator.Element: CollectionType {
static var numberOfDims: Int {
return 1 + Generator.Element.numberOfDims
}
}
[[1],[2],[3]].numberOfDims // return 1 ... boooo!
This same constraint also applies to function overloading.
Type inspection can’t work
If there’s a way to make it work, it would be something along these lines, which uses a conditional instead of type-based method dispatch to traverse the nested array types:
extension Array {
var numberOfDims: Int {
return self.dynamicType.numberOfDims
}
static var numberOfDims: Int {
if let nestedArrayType = Generator.Element.self as? Array.Type {
return 1 + nestedArrayType.numberOfDims
} else {
return 1
}
}
}
[[1,2],[2],[3]].numberOfDims
The code above compiles — quite confusingly — because Swift takes Array.Type to be a shortcut for Array<Element>.Type. That completely defeats the attempt to unwrap.
What’s the workaround? There isn’t one. This approach can’t work because we need to say “if Element is some kind of Array,” but as far as I know, there’s no way in Swift to say “array of anything,” or “just the Array type regardless of Element.”
Everywhere you mention the Array type, its generic type parameter must be materialized to a concrete type or a protocol at compile time.
Cheating can work
What about reflection, then? There is a way. Not a nice way, but there is a way. Swift’s Mirror is currently not powerful enough to tell us what the element type is, but there is another reflection method that is powerful enough: converting the type to a string.
private let arrayPat = try! NSRegularExpression(pattern: "Array<", options: [])
extension Array {
var numberOfDims: Int {
let typeName = "\(self.dynamicType)"
return arrayPat.numberOfMatchesInString(
typeName, options: [], range: NSMakeRange(0, typeName.characters.count))
}
}
Horrid, evil, brittle, probably not legal in all countries — but it works!
Unfortunately I was not able to do this with a Swift array but you can easily convert a swift array to an NSArray.
extension NSArray {
func numberOfDims() -> Int {
var count = 0
if let x = self.firstObject as? NSArray {
count += x.numberOfDims() + 1
} else {
return 1
}
return count
}
}

Function accepting a generic Collection and returning an array of indices

I'm trying to write a function that accepts a generic Collection and a single element, then returns the index or indices of this element as an array. However, I'm getting an error at the return statement.
func findAll<T: Collection, U: Equatable>(_ items: T, _ find: U) -> [U] where T.Iterator.Element == U {
var found = [Int]()
for (index, item) in items.enumerated() {
if item == find {
found.append(index)
}
}
return found
}
Ken's answer is good, but Collection can have an Index other than Int. If you try to use the indexes you get back, you many not be able to subscript with them.
Instead of [Int], you want [Self.Index]. So instead of enumerated, you want the more general zip:
extension Collection where Self.Element: Equatable {
func indicesOfElements(equalTo element: Self.Element) -> [Self.Index] {
return zip(self.indices, self) // Zip together the index and element
.filter { $0.1 == element } // Find the ones that match
.map { $0.0 } // Return the elements
}
}
[1,2,3,4,1].indicesOfElements(equalTo: 1) // => [0,4]
That said, a simpler approach would be:
extension Collection where Self.Element: Equatable {
func indicesOfElements(equalTo element: Self.Element) -> [Self.Index] {
return indices.filter { self[$0] == element }
}
}
To see the problem w/ subscripting, consider this:
let s = "abcabc"
let i = s.indicesOfElements(equalTo: "a").first!
s[i] // "a"
let j = findAll(s, "a").first!
s[j] // error: 'subscript' is unavailable: cannot subscript String with an Int, see the documentation comment for discussion
While a protocol extension is the preferred way to do this in Swift, this is directly convertible to the following generic function syntax:
func indicesOfElements<C: Collection>(in collection: C, equalTo element: C.Element) -> [C.Index]
where C.Element: Equatable {
return collection.indices.filter { collection[$0] == element }
}
The following style is also equivalent, and has a slightly shallower learning curve (no need for filter.
func simplerIndicesOfElements<C: Collection>(in collection: C, equalTo element: C.Element) -> [C.Index]
where C.Element: Equatable {
var results: [C.Index] = []
for index in collection.indices {
if collection[index] == element {
results.append(index)
}
}
return results
}
I believe even fairly new Swift developers should learn to read simple filter and map expressions (though these should aways be kept simple, even by experts!) But there is absolutely nothing wrong with learning simple for iteration first.
If you're just getting started, note the naming style here as well. Your initial example included two unnamed parameters. In many (most) cases this is poor Swift. In Swift we generally try to name our parameters such that they read fairly naturally in English. In findAll(xs, x) it's unclear what the parameters are or what the return value will be in. In indicesOfElements(in: xs, equalTo: x), all the information is available at the call site.
In Swift 3, this takes a lot more syntax than you probably expect:
func indicesOfElements<C: Collection>(in collection: C, equalTo element: C.Iterator.Element) -> [C.Index]
where C.Iterator.Element: Equatable, C.Indices.Iterator.Element == C.Index {
// ... Same body ...
}
In Swift 3, associated types can't have additional constraints put on them. This seems a small thing, but it's huge. It means that there's no way to say Collection.Indices actually contains Collection.Index. And there's no way to create a Collection.Element (the type returned by subscripting the collection) that is promised to be the same as Collection.Iterator.Element (the type returned by iterating over the collection). This leads to a lot of C.Iterator... and where clauses that seem obvious like C.Indices.Iterator.Element == C.Index.
If you're near the start of your Swift journey, I'd probably skip over the generics entirely, and write this in terms of [Int]. A very common mistake by Swift programmers (new and "old") is to jump to generic programming before they have any need of it. But if you're at the stage where you're tackling generics, this is how you often have to write them in Swift 3. (Swift 4 is a dramatic improvement for generic programming.)
Since you would like to return the indices of the found elements, you should return an array of Ints instead of [U]. Here's the updated code:
func findAll<T: Collection, U: Equatable>(_ items: T, _ find: U)
-> [Int] where T.Iterator.Element == U {
var found = [Int]()
for (index, item) in items.enumerated() {
if item == find {
found.append(index)
}
}
return found
}
And here's a test case:
let numbers = [1,0,1,0,0,1,1]
let indicesOfOnes = findAll(numbers, 1)
print(indicesOfOnes)
Which will print:
[0, 2, 5, 6]

Calculate the number of dimensions of a multi-dimensional array in Swift

Suppose I have some function that I want to populate my data structure using a multi-dimensional array (e.g. a Tensor class):
class Tensor {
init<A>(array:A) { /* ... */ }
}
while I could add in a shape parameter, I would prefer to automatically calculate the dimensions from the array itself. If you know apriori the dimensions, it's trivial to read it off:
let d1 = array.count
let d2 = array[0].count
However, it's less clear how to do it for an N-dimensional array. I was thinking there might be a way to do it by extending the Array class:
extension Int {
func numberOfDims() -> Int {
return 0
}
}
extension Array {
func numberOfDims() -> Int {
return 1+Element.self.numberOfDims()
}
}
Unfortunately, this won't (rightfully so) compile, as numberOfDims isn't defined for most types. However, I'm don't see any way of constraining Element, as Arrays-of-Arrays make things complicated.
I was hoping someone else might have some insight into how to solve this problem (or explain why this is impossible).
If you're looking to get the depth of a nested array (Swift's standard library doesn't technically provide you with multi-dimensional arrays, only jagged arrays) – then, as shown in this Q&A, you can use a 'dummy protocol' and typecasting.
protocol _Array {
var nestingDepth: Int { get }
}
extension Array : _Array {
var nestingDepth: Int {
return 1 + ((first as? _Array)?.nestingDepth ?? 0)
}
}
let a = [1, 2, 3]
print(a.nestingDepth) // 1
let b = [[1], [2, 3], [4]]
print(b.nestingDepth) // 2
let c = [[[1], [2]], [[3]], [[4], [5]]]
print(c.nestingDepth) // 3
(I believe this approach would've still worked when you had originally posted the question)
In Swift 3, this can also be achieved without a dummy protocol, but instead by casting to [Any]. However, as noted in the linked Q&A, this is inefficient as it requires traversing the entire array in order to box each element in an existential container.
Also note that this implementation assumes that you're calling it on a homogenous nested array. As Paul notes, it won't give a correct answer for [[[1], 2], 3].
If this needs to be accounted for, you could write a recursive method which will iterate through each of the nested arrays and returning the minimum depth of the nesting.
protocol _Array {
func _nestingDepth(minimumDepth: Int?, currentDepth: Int) -> Int
}
extension Array : _Array {
func _nestingDepth(minimumDepth: Int?, currentDepth: Int) -> Int {
// for an empty array, the minimum depth is the current depth, as we know
// that _nestingDepth is called where currentDepth <= minimumDepth.
guard !isEmpty else { return currentDepth }
var minimumDepth = minimumDepth
for element in self {
// if current depth has exceeded minimum depth, then return the minimum.
// this allows for the short-circuiting of the function.
if let minimumDepth = minimumDepth, currentDepth >= minimumDepth {
return minimumDepth
}
// if element isn't an array, then return the current depth as the new minimum,
// given that currentDepth < minimumDepth.
guard let element = element as? _Array else { return currentDepth }
// get the new minimum depth from the next nesting,
// and incrementing the current depth.
minimumDepth = element._nestingDepth(minimumDepth: minimumDepth,
currentDepth: currentDepth + 1)
}
// the force unwrap is safe, as we know array is non-empty, therefore minimumDepth
// has been assigned at least once.
return minimumDepth!
}
var nestingDepth: Int {
return _nestingDepth(minimumDepth: nil, currentDepth: 1)
}
}
let a = [1, 2, 3]
print(a.nestingDepth) // 1
let b = [[1], [2], [3]]
print(b.nestingDepth) // 2
let c = [[[1], [2]], [[3]], [[5], [6]]]
print(c.nestingDepth) // 3
let d: [Any] = [ [[1], [2], [[3]] ], [[4]], [5] ]
print(d.nestingDepth) // 2 (the minimum depth is at element [5])
Great question that sent me off on a goose chase!
To be clear: I’m talking below about the approach of using the outermost array’s generic type parameter to compute the number of dimensions. As Tyrelidrel shows, you can recursively examine the runtime type of the first element — although this approach gives nonsensical answers for heterogenous arrays like [[[1], 2], 3].
Type-based dispatch can’t work
As you note, your code as written doesn’t work because numberOfDims is not defined for all types. But is there a workaround? Does this direction lead somewhere?
No, it’s a dead end. The reason is that extension methods are statically dispatched for non-class types, as the following snippet demonstrates:
extension CollectionType {
func identify() {
print("I am a collection of some kind")
}
func greetAndIdentify() {
print("Hello!")
identify()
}
}
extension Array {
func identify() {
print("I am an array")
}
}
[1,2,3].identify() // prints "I am an array"
[1,2,3].greetAndIdentify() // prints "Hello!" and "I am a collection of some kind"
Even if Swift allowed you to extend Any (and it doesn’t), Element.self.numberOfDims() would always call the Any implementation of numberOfDims() even if the runtime type of Element.self were an Array.
This crushing static dispatch limitation means that even this promising-looking approach fails (it compiles, but always returns 1):
extension CollectionType {
var numberOfDims: Int {
return self.dynamicType.numberOfDims
}
static var numberOfDims: Int {
return 1
}
}
extension CollectionType where Generator.Element: CollectionType {
static var numberOfDims: Int {
return 1 + Generator.Element.numberOfDims
}
}
[[1],[2],[3]].numberOfDims // return 1 ... boooo!
This same constraint also applies to function overloading.
Type inspection can’t work
If there’s a way to make it work, it would be something along these lines, which uses a conditional instead of type-based method dispatch to traverse the nested array types:
extension Array {
var numberOfDims: Int {
return self.dynamicType.numberOfDims
}
static var numberOfDims: Int {
if let nestedArrayType = Generator.Element.self as? Array.Type {
return 1 + nestedArrayType.numberOfDims
} else {
return 1
}
}
}
[[1,2],[2],[3]].numberOfDims
The code above compiles — quite confusingly — because Swift takes Array.Type to be a shortcut for Array<Element>.Type. That completely defeats the attempt to unwrap.
What’s the workaround? There isn’t one. This approach can’t work because we need to say “if Element is some kind of Array,” but as far as I know, there’s no way in Swift to say “array of anything,” or “just the Array type regardless of Element.”
Everywhere you mention the Array type, its generic type parameter must be materialized to a concrete type or a protocol at compile time.
Cheating can work
What about reflection, then? There is a way. Not a nice way, but there is a way. Swift’s Mirror is currently not powerful enough to tell us what the element type is, but there is another reflection method that is powerful enough: converting the type to a string.
private let arrayPat = try! NSRegularExpression(pattern: "Array<", options: [])
extension Array {
var numberOfDims: Int {
let typeName = "\(self.dynamicType)"
return arrayPat.numberOfMatchesInString(
typeName, options: [], range: NSMakeRange(0, typeName.characters.count))
}
}
Horrid, evil, brittle, probably not legal in all countries — but it works!
Unfortunately I was not able to do this with a Swift array but you can easily convert a swift array to an NSArray.
extension NSArray {
func numberOfDims() -> Int {
var count = 0
if let x = self.firstObject as? NSArray {
count += x.numberOfDims() + 1
} else {
return 1
}
return count
}
}

How to specify that a Dictionary.Value must be an array [duplicate]

func getIndex<T: Equatable>(valueToFind: T) -> Int? {...}
mutating func replaceObjectWithObject<T: Equatable>(obj1: T, obj2: T) {
if let index = self.getIndex(obj1) {
self.removeAtIndex(index)
self.insert(obj2, atIndex: index) // Error here: 'T' is not convertible to 'T'
}
}
I have that function which is suppose to replace an element with another element. But Im not very familiar with Generics and don't know why this is not working. Please help.
If I remove the Equatable from the mutating func the error message jumps to the first line in that func and if I then replace that with the func find() that gives me the same error as on line 3.
This is actually not possible via an extension under the existing system of protocols and generics in Swift - you can't add additional constraints to the generic subtype of a type, so you can't extend Array with a method that requires that its contents conform to Equatable.
You can see this restriction in action with the built-in Array type -- there's no myArray.find(element) method, but there is a global function find() that takes a collection and an element, with a generic constraint that the collection's elements are Equatable:
func find<C : CollectionType where C.Generator.Element : Equatable>(domain: C, value: C.Generator.Element) -> C.Index?
You can do this for your method - you just need to write a similar top-level function:
func replaceObjectWithObject<C : RangeReplaceableCollectionType where C.Generator.Element : Equatable>(inout collection: C, obj1: C.Generator.Element, obj2: C.Generator.Element) {
if let index = find(collection, obj1) {
removeAtIndex(&collection, index)
insert(&collection, obj2, atIndex: index)
}
}
var myArray = [1, 2, 3, 4, 5]
replaceObjectWithObject(&myArray, 2, 7)
// 1, 2, 7, 4, 5
How did you declare your Array extension? The problem is that your generic functions require arguments of type Equatable, but when you declared the array, you specified a specific implementation of an Equatable class, like String. A T is not a String without a cast.
What you are trying to do cannot be done using class/struct functions - #Nate Cook has provided a very good solution using a global function.
By the way the reason why it doesn't work becomes clearer if in your extension methods you replace T with V: they are different types. That also explains why the same error occurs if you remove the dependency from Equatable: the array holds objects of T type, but you are trying to insert a V value.
This answer is for a duplicate question stated her: Create swift array extension for typed arrays
There is a way to solve extensions to Array that are only applicable to a specific type of array. But you have to use an Array with elements of type Any, which sort of circumvents Swift's type system. But the code still works even if there are elements of other types in the array. See example below.
class Job {
var name: String
var id: Int
var completed: Bool
init(name: String, id: Int, completed: Bool) {
self.name = name
self.id = id
self.completed = completed
}
}
var jobs: [Any] = [
Job(name: "Carpenter", id: 32, completed: true),
Job(name: "Engineer", id: 123, completed: false),
Job(name: "Pilot", id: 332, completed: true)]
extension Array {
// These methods are intended for arrays that contain instances of Job
func withId(id: Int) -> Job? {
for j in self {
if (j as? Job)?.id == id {
return j as? Job
}
}
return nil
}
func thatAreCompleted() -> [Job] {
let completedJobs = self.filter { ($0 as? Job) != nil && ($0 as? Job)!.completed}
return completedJobs.map { $0 as! Job }
}
}
jobs.withId(332)
println(jobs.withId(332)?.name)
//prints "Optional("Pilot")"
let completedJobs = jobs.thatAreCompleted().map {$0.name}
println(completedJobs)
//prints "[Carpenter, Pilot]"
You can use extension with a where clause constraint and I'm using Xcode 7.3.1
extension Array where Element: Equatable {
func testEqutability() {
let e1 = self[0]
let e2 = self[1]
if e1 == e2 {//now we can use == to test Element equtability
//do something
}
}
}

Swift: how can String.join() work custom types?

for example:
var a = [1, 2, 3] // Ints
var s = ",".join(a) // EXC_BAD_ACCESS
Is it possible to make the join function return "1,2,3" ?
Extend Int (or other custom types) to conform to some protocols ?
From Xcode 7.0 beta 6 in Swift 2 now you should use [String].joinWithSeparator(",").
In your case you still need to change Int to String type, therefore I added map().
var a = [1, 2, 3] // [1, 2, 3]
var s2 = a.map { String($0) }.joinWithSeparator(",") // "1,2,3"
From Xcode 8.0 beta 1 in Swift 3 code slightly changes to
[String].joined(separator: ",").
var s3 = a.map { String($0) }.joined(separator: ",") // "1,2,3"
try this
var a = [1, 2, 3] // Ints
var s = ",".join(a.map { $0.description })
or add this extension
extension String {
func join<S : SequenceType where S.Generator.Element : Printable>(elements: S) -> String {
return self.join(map(elements){ $0.description })
}
// use this if you don't want it constrain to Printable
//func join<S : SequenceType>(elements: S) -> String {
// return self.join(map(elements){ "\($0)" })
//}
}
var a = [1, 2, 3] // Ints
var s = ",".join(a) // works with new overload of join
join is defined as
extension String {
func join<S : SequenceType where String == String>(elements: S) -> String
}
which means it takes a sequence of string, you can't pass a sequence of int to it.
And just to make your life more complete, starting from Xcode 8.0 beta 1 in Swift 3 you should NOW use [String].joined(separator: ",").
This is the new "ed/ing" naming rule for Swift APIs:
Name functions and methods according to their side-effects
Those without side-effects should read as noun phrases, e.g. x.distance(to: y), i.successor().
Those with side-effects should read as imperative verb phrases, e.g., print(x), x.sort(), x.append(y).
Name Mutating/nonmutating method pairs consistently. A mutating method will often have a nonmutating variant with similar semantics, but that returns a new value rather than updating an instance in-place.
Swift: API Design Guidelines
The simplest way is a variation of #BryanChen's answer:
",".join(a.map { String($0) } )
Even if you can't make join work for custom types, there's an easy workaround.
All you have to do is define a method on your class (or extend a built-in class) to return a string, and then map that into the join.
So, for example, we could have:
extension Int {
func toString() -> String {
return "\(self)" // trivial example here, but yours could be more complex
}
Then you can do:
let xs = [1, 2, 3]
let s = join(xs.map { $0.toString() })
I wouldn't recommend using .description for this purpose, as by default it will call .debugDescription, which is not particularly useful in production code.
In any case, it would be better to provide an explicit method for transforming into a string suitable for joining, rather than relying on a generic 'description' method which you may change at a later date.
A Swift 3 solution
public extension Sequence where Iterator.Element: CustomStringConvertible {
func joined(seperator: String) -> String {
return self.map({ (val) -> String in
"\(val)"
}).joined(separator: seperator)
}
}