ios 在 NSPredicate 中结合“AND”和“OR”条件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10317692/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 18:04:13  来源:igfitidea点击:

Combining 'AND' and 'OR' Condition in NSPredicate

ioscore-datanspredicate

提问by dubbeat

Back again needing more help with constructing my NSPredicates :(

再次需要更多帮助来构建我的 NSPredicates :(

Category
{
   name:string
   subs<-->>SubCategory
}

SubCategory
{
   name:string
   numbervalue:NSNumber
}

I would like to know how to create a predicate with ANDand OR.

我想知道如何使用ANDOR创建谓词。

For example, I would like to return every Category with name == "category_name" that also has a subcategory with a numbervalue of "valueA" OR"valueB".

例如,我想返回名称 == "category_name" 的每个类别,该类别还有一个数字值为 "valueA""valueB"的子类别。

I've tried every possible combination of predicate constructors I could come up with but I just cant get it to work.

我已经尝试了我能想到的所有可能的谓词构造函数组合,但我就是无法让它工作。

This is my best attempt so far.

这是我迄今为止最好的尝试。

NSPredicate *predicate=[NSPredicate predicateWithFormat@"(name== %@) AND (ANY subs.numbervalue==%@ OR ANY subs.numbervalue==%@)", @"aname", value1, value2];

Edit 1

编辑 1

Second attempt. The filtering on the 'numbervalue' is still not working.

第二次尝试。对“数值”的过滤仍然无效。

NSNumber valueA=[NSNumber numberWithInt:20];
NSNumber valueA=[NSNumber numberWithInt:90];
NSArray *arr=[NSArray arrayWithObject:valueA,valueB,nil];

predicate=[NSPredicate predicateWithFormat:@"(name==%@)AND(ANY subs.numbervalue IN %@)",@"aname",arr];

Edit 2

编辑 2

I've tried filtering just by numberValue and have left the name out alltogether.

我试过仅按 numberValue 进行过滤,并将名称完全排除在外。

1) using this results in the entire set being returned even if only 1 item in the set has the value.

1) 使用此结果会返回整个集合,即使集合中只有 1 个项目具有该值。

predicate=[NSPredicate predicateWithFormat:@"(ANY subs.numbervalue IN %@)",arr];

2) Using this results in the same problem, every item in the set being returned even if only 1 of them matches.

2) 使用它会导致同样的问题,即使其中只有 1 个匹配,也会返回集合中的每个项目。

predicate=[NSPredicate predicateWithFormat:@"((SUBQUERY(subs, $x, $x.numbervalue == %@ or $x.numbervalue == %@).@count > 0)", value1, value2];

Also using the simplest version results in the same problem.... I didnt notice this earlier.

同样使用最简单的版本会导致同样的问题......我之前没有注意到这一点。

NSPredicate *predicate=[NSPredicate predicateWithFormat@"(ANY subs.numbervalue==%@ ,valueA];

So I think I have my problem narrowed down.

所以我想我的问题缩小了。

Category is an Entity. SubCategory is an Entity.

类别是一个实体。子类别是一个实体。

Category has a one to many relationship with SubCategory and is represented as an NSSet of SubCategory.

Category 与 SubCategory 是一对多的关系,表示为 SubCategory 的 NSSet。

Each SubCategory has an attribute named numbervalue.

每个 SubCategory 都有一个名为 numbervalue 的属性。

Edit 3

编辑 3

To test I have 2 Categorys. Both Categories have 10 subs, each with a numbervalue of 1 -10;

为了测试,我有 2 个类别。两个类别都有 10 个子项,每个子项的数值为 1 -10;

Using this code both categories are returned along with all 10 subs for each.

使用此代码返回两个类别以及每个类别的所有 10 个子项。

Expected result is both categories returned , each with just 2 subs.

预期结果是返回两个类别,每个类别只有 2 个子项。

I've traced out all my objects and the data is correct. The problem is I cant return a category that has filtered subs.

我已经找出了我所有的对象并且数据是正确的。问题是我无法返回已过滤子项的类别。

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSManagedObjectContext *context=[[DataSource sharedDataSource]managedObjectContext];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Category" inManagedObjectContext:context];
[fetchRequest setEntity:entity];

[fetchRequest setFetchBatchSize:20];

NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObjects:sortDescriptor, nil];

NSPredicate *predicate;
NSNumber *a=[NSNumber numberWithFloat:1];
NSNumber *b=[NSNumber numberWithFloat:2];
predicate=[NSPredicate predicateWithFormat:@"(SUBQUERY(subs,$x,$x.numbervalue==%@ or $x.numbervalue==%@).@count> 0)",a,b];

[fetchRequest setPredicate:predicate];
[fetchRequest setSortDescriptors:sortDescriptors];

NSError *error = nil;
[NSFetchedResultsContoller deleteCacheWithName:nil];

NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:context sectionNameKeyPath:@"name" cacheName:@"Master"];
aFetchedResultsController.delegate = self;

self.fetchedResultsController = aFetchedResultsController;

if (![self.fetchedResultsController performFetch:&error]) {

   NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
   abort();
}

采纳答案by Lorenzo B

I'll do the following using a SUBQUERY.

我将使用SUBQUERY.

[NSPredicate predicateWithFormat@"(name == %@) AND (SUBQUERY(subs, $x, $x.numbervalue == %@ or $x.numbervalue == %@).@count > 0)", @"aname", value1, value2];

Try it and let me know.

试试吧,让我知道。

Another solution could be to grab the whole collection subsand then filter the retrieved set with a predicate to check if elements match for value1or value2.

另一种解决方案可能是获取整个集合subs,然后使用谓词过滤检索到的集合以检查元素是否与value1或匹配value2

Hope it helps.

希望能帮助到你。

Edit

编辑

If you follow Eimantassuggestion make to sure to create the right array:

如果您遵循Eimantas 的建议,请确保创建正确的数组:

NSNumber valueA = [NSNumber numberWithInt:20];
NSNumber valueB = [NSNumber numberWithInt:90];
NSArray *arr = [NSArray arrayWithObjects:valueA, valueB, nil];

回答by Onur Var

Addition to @Stuart's answer, you can use NSCompoundPredicate for your OR & AND operations like this.

除了@Stuart 的回答之外,您还可以将 NSCompoundPredicate 用于这样的 OR & AND 操作。

Obj-C - OR

对象-C - 或

// OR Condition //

NSPredicate *predicate1 = [NSPredicate predicateWithFormat:@"X == 1"];
NSPredicate *predicate2 = [NSPredicate predicateWithFormat:@"X == 2"];
NSPredicate *predicate = [NSCompoundPredicate orPredicateWithSubpredicates:@[predicate1, predicate2]];

Obj-C - AND

Obj-C - 与

NSPredicate *predicate1 = [NSPredicate predicateWithFormat:@"X == 1"];
NSPredicate *predicate2 = [NSPredicate predicateWithFormat:@"X == 2"];
NSPredicate *predicate = [NSCompoundPredicate andPredicateWithSubpredicates:@[predicate1, predicate2]];

Swift - OR

斯威夫特 - 或

let predicate1:NSPredicate = NSPredicate(format: "X == 1")
let predicate2:NSPredicate = NSPredicate(format: "Y == 2")
let predicate:NSPredicate  = NSCompoundPredicate(orPredicateWithSubpredicates: [predicate1,predicate2] )

Swift - AND

斯威夫特 - 和

let predicate1:NSPredicate = NSPredicate(format: "X == 1")
let predicate2:NSPredicate = NSPredicate(format: "Y == 2")
let predicate:NSPredicate  = NSCompoundPredicate(andPredicateWithSubpredicates: [predicate1,predicate2] )

Swift 3 - OR

斯威夫特 3 - 或

    let predicate1 = NSPredicate(format: "X == 1")
    let predicate2 = NSPredicate(format: "Y == 2")
    let predicateCompound = NSCompoundPredicate.init(type: .or, subpredicates: [predicate1,predicate2])

Swift 3 - AND

斯威夫特 3 - 和

    let predicate1 = NSPredicate(format: "X == 1")
    let predicate2 = NSPredicate(format: "Y == 2")
    let predicateCompound = NSCompoundPredicate.init(type: .and, subpredicates: [predicate1,predicate2])

回答by Stuart P.

Another option is to use an NSCompoundPredicate (note andPredicateWithSubpredicates does an AND but there are a few options to use, this should be much more efficient than doing 2 searches)

另一种选择是使用 NSCompoundPredicate (注意 andPredicateWithSubpredicates 执行 AND 但有几个选项可以使用,这应该比执行 2 次搜索更有效)

https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSCompoundPredicate_Class/index.html#//apple_ref/occ/clm/NSCompoundPredicate/andPredicateWithSubpredicates:)

https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSCompoundPredicate_Class/index.html#//apple_ref/occ/clm/NSCompoundPredicate/andPredicateWithSubpredicates:)

回答by zeeshan

For Swift, this is how you can do it:

对于 Swift,您可以这样做:

SWIFT 4.x - AND

SWIFT 4.x - 和

        let p0 = NSPredicate(format: "X == 1")
        let p1 = NSPredicate(format: "Y == 2")
        fetchRequest.predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [p0, p1])

SWIFT 4.x - OR

SWIFT 4.x - 或

        let p0 = NSPredicate(format: "X == 1")
        let p1 = NSPredicate(format: "Y == 2")
        fetchRequest.predicate = NSCompoundPredicate(orPredicateWithSubpredicates: [p0, p1])

SWIFT 4.x - NOT

SWIFT 4.x - 不是

        let p0 = NSPredicate(format: "X == 1")
        let p1 = NSPredicate(format: "Y == 2")
        fetchRequest.predicate = NSCompoundPredicate(notPredicateWithSubpredicates: [p0, p1])

Example

例子

This is an example from one of my codes, where I look for uid and sync:

这是我的一个代码中的一个示例,我在其中查找 uid 和 sync:

        let p0 = NSPredicate(format: self.uid + " = '" + uid + "'")
        let p1 = NSPredicate(format: self.sync + " = %@", NSNumber(value: true as Bool))
        fetchRequest.predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [p0, p1])