Filter array on type

When I try to filter an array of base types to produce an array of more specific subtypes, I get a compiler error.


class X {

var v: Int

init(_ v:Int) { self.v = v }

}

class X1:X{}

class X2:X{}


var a:[X]

var a1:[X1]

a = [X1(1),X1(2),X2(3),X2(4),X1(5)]

a[0].v

a1 = a.filter { $0 is X1 } // ERROR

a1[2].v


The error I get is:


Playground execution failed: playground78.swift:15:8: error: cannot invoke 'filter' with an argument list of type '(@noescape (X) throws -> Bool)'

a1 = a.filter { $0 is X1 }

^

playground78.swift:15:8: note: expected an argument list of type '(@noescape (Self.Generator.Element) throws -> Bool)'

a1 = a.filter { $0 is X1 }


Even if I explicitly specify the types it fails the same way:


a1 = a.filter { (p:X) -> Bool in p is X1 }


Why is this failing? Can anyone suggest ways to filter to produce a collection of subclass?


I am using XCode Version 7.2 (7C68) (Swift 2.1)

Accepted Reply

What is bad is this:

    var a1:[X1]


Where `a` is of type [X], the return type of `filter` is [X], which cannot be [X1] even if all elements are X1.

Try this:

a1 = a.filter(f) as! [X1]

Or this:

a1 = a.flatMap{$0 as? X1}

Replies

What is bad is this:

    var a1:[X1]


Where `a` is of type [X], the return type of `filter` is [X], which cannot be [X1] even if all elements are X1.

Try this:

a1 = a.filter(f) as! [X1]

Or this:

a1 = a.flatMap{$0 as? X1}

@OOper, Thanks. You spotted the problem. filter returns [X].


flatMap works even if X is a protocol. "filter(f) as! [X1]" does not work if X is a protocol since it cannot be cast to the type of X1. However this third solution works when X is a protocol:


return (a.filter { $0 is XValue }).map { $0 as! XValue }