उद्देश्य-सी में एक नए NSArray में NSArray को फ़िल्टर करना


121

मेरे पास एक है NSArrayऔर मैं NSArrayमूल सरणी से ऑब्जेक्ट के साथ एक नया बनाना चाहता हूं जो कुछ मानदंडों को पूरा करता है। मानदंड एक फ़ंक्शन द्वारा तय किया जाता है जो एक रिटर्न देता है BOOL

मैं NSMutableArrayस्रोत सरणी के माध्यम से एक , पुनरावृति बना सकता हूं और उन वस्तुओं पर प्रतिलिपि बना सकता हूं जिन्हें फ़िल्टर फ़ंक्शन स्वीकार करता है और फिर इसका एक अपरिवर्तनीय संस्करण बनाता है।

क्या कोई बेहतर तरीका है?

जवाबों:


140

NSArrayऔर NSMutableArrayसरणी सामग्री को फ़िल्टर करने के लिए तरीके प्रदान करते हैं। FilteredArrayUsingPredicateNSArray प्रदान करता है: जो रिसीवर में एक नई सरणी देता है जो निर्दिष्ट विधेय से मेल खाता है। filterUsingPredicate कोNSMutableArray जोड़ता है : जो निर्दिष्ट विधेय के खिलाफ रिसीवर की सामग्री का मूल्यांकन करता है और केवल उन वस्तुओं को छोड़ देता है जो मेल खाते हैं। इन तरीकों को निम्नलिखित उदाहरण में चित्रित किया गया है।

NSMutableArray *array =
    [NSMutableArray arrayWithObjects:@"Bill", @"Ben", @"Chris", @"Melissa", nil];

NSPredicate *bPredicate =
    [NSPredicate predicateWithFormat:@"SELF beginswith[c] 'b'"];
NSArray *beginWithB =
    [array filteredArrayUsingPredicate:bPredicate];
// beginWithB contains { @"Bill", @"Ben" }.

NSPredicate *sPredicate =
    [NSPredicate predicateWithFormat:@"SELF contains[c] 's'"];
[array filteredArrayUsingPredicate:sPredicate];
// array now contains { @"Chris", @"Melissa" }

84
मैंने पापा स्मर्फ की पॉडकास्ट सुनी और पापा स्मर्फ ने कहा कि जवाब स्टैकऑवरफ्लो में रहना चाहिए ताकि समुदाय को रेट कर सकें और उनमें सुधार कर सकें।
विल्क 2

10
@mmalc - शायद अधिक स्पष्ट, लेकिन निश्चित रूप से इसे यहाँ देखने के लिए अधिक सुविधाजनक है।
ब्रायन

5
NSPredicate मर चुका है, लंबे समय तक जीवित ब्लॉक! सीएफ मेरा जवाब नीचे।
क्ले ब्रिजेस

क्या शामिल है [सी] मतलब है? मैं हमेशा [c] देखता हूं लेकिन मुझे समझ नहीं आता कि यह क्या करता है?
user1007522

3
@ user1007522, [c] मैच के मामले को असंवेदनशील बनाता है
जोंबाउर

104

इसे करने के तरीकों के भार हैं, लेकिन अब तक सबसे साफ जरूर है [NSPredicate predicateWithBlock:]:

NSArray *filteredArray = [array filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id object, NSDictionary *bindings) {
    return [object shouldIKeepYou];  // Return YES for each object you want in filteredArray.
}]];

मुझे लगता है कि इस बारे में संक्षिप्त रूप में यह हो जाता है।


स्विफ्ट:

NSArrayस्विफ्ट में s के साथ काम करने वालों के लिए , आप इसे और भी संक्षिप्त संस्करण पसंद कर सकते हैं :

nsArray = nsArray.filter { $0.shouldIKeepYou() }

filterसिर्फ एक तरीका है Array( NSArrayस्विफ्ट के लिए निहित है Array)। यह एक तर्क लेता है: एक बंद जो सरणी में एक वस्तु लेता है और एक लौटता है Bool। अपने बंद होने trueमें, फ़िल्टर की गई सरणी में इच्छित किसी भी ऑब्जेक्ट के लिए वापस लौटें ।


1
यहाँ क्या भूमिका निभा रहा है?
कातीन

NSPredicate predicateWithBlock:एपीआई द्वारा @Kitain बाइंडिंग की आवश्यकता है ।
थॉमस डब्ल्यूएपी

@Kaainain bindingsशब्दकोश में टेम्प्लेट के लिए वैरिएबल बाइंडिंग हो सकते हैं।
अमीन नेग्म-अवध

जटिल वस्तुओं से निपटने के दौरान स्वीकृत उत्तर की तुलना में बहुत अधिक उपयोगी :)
बेन लेगियरियो

47

क्ले ब्रिजेस के उत्तर के आधार पर, यहां ब्लॉकों का उपयोग करके फ़िल्टर करने का एक उदाहरण है ( yourArrayआपके सरणी चर नाम में परिवर्तन और testFuncआपके परीक्षण फ़ंक्शन के नाम पर):

yourArray = [yourArray objectsAtIndexes:[yourArray indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
    return [self testFunc:obj];
}]];

अंत में एक जवाब न केवल ब्लॉकों के साथ फ़िल्टरिंग का उल्लेख करता है, बल्कि यह भी कि यह कैसे करना है पर एक अच्छा उदाहरण दे रहा है। धन्यवाद।
क्रिस्टियन

मुझे यह उत्तर पसंद है; भले ही filteredArrayUsingPredicateआप दुबले हों, इस तथ्य का कि आप किसी भी प्रकार के अस्पष्ट उद्देश्य का उपयोग नहीं करते हैं।
जेम्स पेरिह

यह ऐसा करने का सबसे आधुनिक तरीका है। व्यक्तिगत रूप से मैं पुराने शॉर्टहैंड "ऑब्जेक्ट्सपासिंगटेस्ट" के लिए लंबे समय से हूं जो निश्चित बिंदु पर एपीआई से गायब हो गया था। फिर भी यह तेज और अच्छा चलता है। मुझे NSPredicate पसंद है - लेकिन अन्य चीजों के लिए, जहाँ भारी हथौड़े की ज़रूरत होती है
Motti Shneor

अब आपको त्रुटि मिलेगी Implicit conversion of 'NSUInteger' (aka 'unsigned long') to 'NSIndexSet * _Nonnull' is disallowed with ARC... यह उम्मीद करता है कि NSIndexSets
anup4real

@ अनूप 4 असली, मुझे लगता है कि आपके द्वारा बताई गई चेतावनी का कारण यह है कि आपने गलती से इसका उपयोग indexOfObjectPassingTestकिया था indexesOfObjectsPassingTest। याद करने में आसान, लेकिन बड़ा अंतर :)
pckill

46

यदि आप OS X 10.6 / iOS 4.0 या बाद के संस्करण हैं, तो आप शायद NSPredicate की तुलना में ब्लॉक के साथ बेहतर हैं। -[NSArray indexesOfObjectsPassingTest:]आसान -select:या -filter:विधि ( उदाहरण ) जोड़ने के लिए अपनी खुद की श्रेणी देखें या लिखें ।

क्या कोई और उस श्रेणी को लिखना चाहता है, इसका परीक्षण करना है, आदि? की जाँच करें BlocksKit ( सरणी डॉक्स )। और कई और उदाहरण मिलते हैं, जैसे, "nsarray block category select" जैसे खोज ।


5
क्या आप एक उदाहरण के साथ अपने उत्तर का विस्तार करेंगे? ब्लॉग वेबसाइटों में मरने की प्रवृत्ति होती है जब आपको उनकी सबसे अधिक आवश्यकता होती है।
दान अब्रामोव

8
लिंक रोट के खिलाफ सुरक्षा संबंधित लेखों से संबंधित कोड और व्हाट्सएप को जोड़ना है, न कि अधिक लिंक जोड़ना। लिंक रखें, लेकिन कुछ उदाहरण कोड जोड़ें।
टूलबियर

3
@ClayBridges मुझे यह प्रश्न कोको में फ़िल्टर करने के तरीकों की तलाश में मिला। चूंकि आपके उत्तर में कोई कोड नमूने नहीं हैं, इसलिए मुझे आपके लिंक के माध्यम से खुदाई करने में लगभग 5 मिनट का समय लगा, ताकि यह पता लगाया जा सके कि ब्लॉक को मेरी आवश्यकता नहीं है। यदि कोड उत्तर में होता तो शायद 30 सेकंड लगते। यह उत्तर वास्तविक कोड के बिना एफएआर कम उपयोगी है।
N_A

1
@mydogisbox et alia: यहाँ केवल 4 उत्तर हैं, और इस प्रकार आपके स्वयं के चमकदार और बेहतर कोड-सैंपल-अप उत्तर के लिए बहुत जगह है। मैं खुश हूं, इसलिए कृपया इसे अकेला छोड़ दें।
क्ले ब्रिज

2
इस बिंदु पर mydogisbox सही है; यदि आप कर रहे हैं सब एक लिंक प्रदान कर रहा है, यह वास्तव में एक जवाब नहीं है, भले ही आप अधिक लिंक जोड़ते हैं। Meta.stackexchange.com/questions/8231 देखें । लिटमस टेस्ट: क्या आपका जवाब अपने दम पर खड़ा हो सकता है, या क्या इसे किसी भी मूल्य के लिंक पर क्लिक करने की आवश्यकता है? विशेष रूप से, आप कहते हैं "आप शायद NSPredicate की तुलना में ब्लॉक के साथ बेहतर हैं," लेकिन आप वास्तव में क्यों नहीं समझाते हैं।
रॉबर्ट हार्वे

16

यह मानते हुए कि आपकी वस्तुएं समान प्रकार की हैं, आप उनके बेस क्लास की श्रेणी के रूप में एक विधि जोड़ सकते हैं जो आपके द्वारा उपयोग किए जा रहे फ़ंक्शन को कॉल करता है। फिर एक NSPredicate ऑब्जेक्ट बनाएं जो उस विधि को संदर्भित करता है।

कुछ श्रेणी में अपने तरीके को परिभाषित करें जो आपके फ़ंक्शन का उपयोग करता है

@implementation BaseClass (SomeCategory)
- (BOOL)myMethod {
    return someComparisonFunction(self, whatever);
}
@end

फिर आप जहाँ भी फ़िल्टरिंग करेंगे:

- (NSArray *)myFilteredObjects {
    NSPredicate *pred = [NSPredicate predicateWithFormat:@"myMethod = TRUE"];
    return [myArray filteredArrayUsingPredicate:pred];
}

बेशक, अगर आपका कार्य केवल आपके वर्ग के भीतर से आने वाली संपत्तियों के खिलाफ तुलना करता है, तो फ़ंक्शन की शर्तों को विधेय स्ट्रिंग में परिवर्तित करना आसान हो सकता है।


मुझे यह उत्तर पसंद आया, क्योंकि यह सुशोभित और संक्षिप्त है, और शॉर्ट-कट को फिर से सीखने की ज़रूरत है कि कैसे सबसे बुनियादी चीज़ के लिए एक NSPredicate को औपचारिक रूप दिया जाए - संपत्तियों और बूलियन-विधि तक पहुंच। मुझे भी लगता है कि रैपर की जरूरत नहीं थी। एक साधारण [myArray फ़िल्टर्डArrayUsingPredicate: [NSPredicate predicateWithFormat: @ "myMethod = TRUE"]]; पर्याप्त होगा। धन्यवाद! (मैं विकल्प के रूप में अच्छी तरह से प्यार करता हूँ, लेकिन यह एक अच्छा है)।
मोति श्नोर

3

NSPredicateएक संग्रह फिल्टर करने के लिए शर्त के निर्माण की NextStep का तरीका है ( NSArray, NSSet, NSDictionary)।

उदाहरण के लिए दो सरणियों पर विचार करें arrऔर filteredarr:

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF contains[c] %@",@"c"];

filteredarr = [NSMutableArray arrayWithArray:[arr filteredArrayUsingPredicate:predicate]];

फ़िल्टर्ड के पास निश्चित रूप से वे आइटम होंगे जिनमें अकेले चरित्र c शामिल हैं।

उन लोगों को याद रखना आसान है, जिनकी पृष्ठभूमि बहुत कम है

*--select * from tbl where column1 like '%a%'--*

1) tbl -> संग्रह से * का चयन करें

2) कॉलम 1 जैसे '% a%' ->NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF contains[c] %@",@"c"];

3) का चयन करें * tbl से जहां column1 जैसे '% a%' ->

[NSMutableArray arrayWithArray:[arr filteredArrayUsingPredicate:predicate]];

आशा है कि ये आपकी मदद करेगा


2

NSArray + Xh

@interface NSArray (X)
/**
 *  @return new NSArray with objects, that passing test block
 */
- (NSArray *)filteredArrayPassingTest:(BOOL (^)(id obj, NSUInteger idx, BOOL *stop))predicate;
@end

NSArray + Xm

@implementation NSArray (X)

- (NSArray *)filteredArrayPassingTest:(BOOL (^)(id obj, NSUInteger idx, BOOL *stop))predicate
{
    return [self objectsAtIndexes:[self indexesOfObjectsPassingTest:predicate]];
}

@end

आप इस श्रेणी को यहाँ डाउनलोड कर सकते हैं


0

इस लाइब्रेरी की जाँच करें

https://github.com/BadChoice/Collection

यह एक बार फिर से लूप न लिखने के लिए बहुत सारे आसान सरणी फ़ंक्शन के साथ आता है

तो आप बस कर सकते हैं:

NSArray* youngHeroes = [self.heroes filter:^BOOL(Hero *object) {
    return object.age.intValue < 20;
}];

या

NSArray* oldHeroes = [self.heroes reject:^BOOL(Hero *object) {
    return object.age.intValue < 20;
}];

0

सबसे अच्छा और आसान तरीका है इस विधि और पास ऐरे और मान को बनाना:

- (NSArray *) filter:(NSArray *)array where:(NSString *)key is:(id)value{
    NSMutableArray *temArr=[[NSMutableArray alloc] init];
    for(NSDictionary *dic in self)
        if([dic[key] isEqual:value])
            [temArr addObject:dic];
    return temArr;
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.