31331


以下の配列arrayから、４以上で、なおかつ2で割り切れる数字を取り出したいです。

[code]

    let array:NSArray = [1,2,3,4,5,6,7,8,9,10]
    
[/code]

例えば、以下のように余りを求める`%2`を記述するとエラーが出ます。

[code]

    let predicate = NSPredicate(format: "SELF > 4 AND SELF%2 == 0")
    array.filtered(using: predicate)
    
[/code]


CC BY-SA 3.0
2016-12-23T05:33:10.623
31329
2017-07-21T18:04:16.323
2017-07-21T18:04:16.323
754
17376
question
swift ios macos swift3
NSPredicateで余りを求める%を記述するにはどうしたら良いでしょうか


残念ながら`NSPredicate`の演算子には、剰余を求めるものは無いようです。(ちなみに`%`はフォーマット用のパラメータとみなされるので、不正な形式のフォーマットを指定するとエラー落ちします。)

[BNF Definition of Cocoa
Predicates](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/Predicates/Articles/pBNF.html#//apple_ref/doc/uid/TP40001796-CJBDBHCB)

ただ英語ありで検索をかけるとこんな記事が出てきました。

[How to fetch even and odd values from core data using
Predicate](https://stackoverflow.com/q/36605430/6541007)

どうやらきちんと明記されたドキュメントは見当たりませんが、`NSExpression`での定義済み関数はどれも使えるようです。

(NSExpression.hより)※ちと長いので綺麗に桁合わせできていません。悪しからず。

>
[code]

>     // Predefined functions are:
>     // name              parameter array contents             returns
>
> //-------------------------------------------------------------------------------------------------------------------------------------
>     // sum:              NSExpression instances representing numbers
> NSNumber
>     // count:            NSExpression instances representing numbers
> NSNumber
>     // min:              NSExpression instances representing numbers
> NSNumber  
>     // max:              NSExpression instances representing numbers
> NSNumber
>     // average:          NSExpression instances representing numbers
> NSNumber
>     // median:           NSExpression instances representing numbers
> NSNumber
>     // mode:             NSExpression instances representing numbers
> NSArray     (returned array will contain all occurrences of the mode)
>     // stddev:           NSExpression instances representing numbers
> NSNumber
>     // add:to:           NSExpression instances representing numbers
> NSNumber
>     // from:subtract:    two NSExpression instances representing numbers
> NSNumber
>     // multiply:by:      two NSExpression instances representing numbers
> NSNumber
>     // divide:by:        two NSExpression instances representing numbers
> NSNumber
>     // modulus:by:       two NSExpression instances representing numbers
> NSNumber
>     // sqrt:             one NSExpression instance representing numbers
> NSNumber
>     // log:              one NSExpression instance representing a number
> NSNumber
>     // ln:               one NSExpression instance representing a number
> NSNumber
>     // raise:toPower:    one NSExpression instance representing a number
> NSNumber
>     // exp:              one NSExpression instance representing a number
> NSNumber
>     // floor:            one NSExpression instance representing a number
> NSNumber
>     // ceiling:          one NSExpression instance representing a number
> NSNumber
>     // abs:              one NSExpression instance representing a number
> NSNumber
>     // trunc:            one NSExpression instance representing a number
> NSNumber
>     // uppercase:        one NSExpression instance representing a string
> NSString
>     // lowercase:        one NSExpression instance representing a string
> NSString
>     // random            none                         NSNumber (integer)
>     // randomn:          one NSExpression instance representing a number
> NSNumber (integer) such that 0 <= rand < param
>     // now               none                         [NSDate now]
>     // bitwiseAnd:with:  two NSExpression instances representing numbers
> NSNumber    (numbers will be treated as NSInteger)
>     // bitwiseOr:with:   two NSExpression instances representing numbers
> NSNumber    (numbers will be treated as NSInteger)
>     // bitwiseXor:with:  two NSExpression instances representing numbers
> NSNumber    (numbers will be treated as NSInteger)
>     // leftshift:by:     two NSExpression instances representing numbers
> NSNumber    (numbers will be treated as NSInteger)
>     // rightshift:by:    two NSExpression instances representing numbers
> NSNumber    (numbers will be treated as NSInteger)
>     // onesComplement:   one NSExpression instance representing a numbers
> NSNumber    (numbers will be treated as NSInteger)
>     // noindex:          an NSExpression                  parameter   (used
> by CoreData to indicate that an index should be dropped)
>     // distanceToLocation:fromLocation: two NSExpression instances
> representing CLLocations    NSNumber
>     // length:           an NSExpression instance representing a string
> NSNumber
>  
[/code]

※一部は`NSArray`には使えてもCore Data等のクエリーには使えない可能性があります。

[code]

    let array: NSArray = [1,2,3,4,5,6,7,8,9,10]
    
    let predicate = NSPredicate(format: "SELF > 4 AND modulus:by:(SELF,2) == 0")
    array.filtered(using: predicate)
    
[/code]

* * *

またCore Data等に使う必要が無いと言う前提なら、自前のメソッドを呼び出すこともできるようです。

[code]

    extension NSNumber {
        @objc func isEven() -> NSNumber {
            return (self.intValue % 2 == 0) as NSNumber
        }
    }
    
    let predicate2 = NSPredicate(format: "SELF > 4 AND FUNCTION(SELF,'isEven')==1")
    array.filtered(using: predicate2)
    
[/code]

* * *

なお _配列から_ と言うのを本当に大前提として良いのであれば、Swiftの`Array`の`filter`メソッドを使った方が簡単でしょう。

[code]

    let arr: [Int] = [1,2,3,4,5,6,7,8,9,10]
    
    let result = arr.filter { $0 > 4 && $0 % 2 == 0 }
    print(result) //->[6, 8, 10]
    
[/code]


CC BY-SA 3.0
2016-12-23T06:32:22.460
31331
2016-12-23T06:32:22.460
2017-05-23T12:38:56.467
-1
13972
31329
answer