उद्देश्य-सी में NSMutableArray से डुप्लिकेट मान निकालने का सबसे अच्छा तरीका?


147

उद्देश्य-सी में डुप्लिकेट मान ( NSString) को हटाने का सबसे अच्छा तरीका NSMutableArray?

क्या इसे करने का सबसे आसान और सही तरीका है?

uniquearray = [[NSSet setWithArray:yourarray] allObjects];

5
आप स्पष्ट करना चाहते हैं कि क्या आप उसी वस्तु के संदर्भ को समाप्त करना चाहते हैं, या वे भी जो अलग-अलग वस्तुएं हैं लेकिन हर क्षेत्र के लिए समान मूल्य हैं।
Amagrammer

क्या एरे की कोई कॉपी बनाए बिना ऐसा करने का कोई तरीका नहीं है?
hfossli

यह रास्ता काफी आसान है और शायद सबसे अच्छा है। लेकिन उदाहरण के लिए यह मेरे मामले के लिए काम नहीं करेगा - सरणी के आइटम पूर्ण डुप्लिकेट नहीं हैं और इसकी तुलना एक संपत्ति से की जानी चाहिए।
व्याचेस्लाव गेरिकोव

एक बार इसके लिए प्रयास करें .. stackoverflow.com/a/38007095/3908884
दोशी

जवाबों:


242

आपका NSSetदृष्टिकोण सबसे अच्छा है यदि आप वस्तुओं के आदेश के बारे में चिंतित नहीं हैं, लेकिन फिर से, यदि आप आदेश के बारे में चिंतित नहीं हैं, तो आप उन्हें NSSetशुरू करने के लिए क्यों नहीं संग्रहीत कर रहे हैं ?

मैंने 2009 में नीचे उत्तर लिखा था; 2011 में, Apple ने NSOrderedSetiOS 5 और Mac OS X 10.7 में जोड़ा । एल्गोरिथ्म क्या था अब कोड की दो लाइनें हैं:

NSOrderedSet *orderedSet = [NSOrderedSet orderedSetWithArray:yourArray];
NSArray *arrayWithoutDuplicates = [orderedSet array];

यदि आप आदेश के बारे में चिंतित हैं और आप iOS 4 या उससे पहले के संस्करण पर चल रहे हैं, तो सरणी की एक प्रति पर लूप करें:

NSArray *copy = [mutableArray copy];
NSInteger index = [copy count] - 1;
for (id object in [copy reverseObjectEnumerator]) {
    if ([mutableArray indexOfObject:object inRange:NSMakeRange(0, index)] != NSNotFound) {
        [mutableArray removeObjectAtIndex:index];
    }
    index--;
}
[copy release];

53
यदि आपको विशिष्टता और आदेश की आवश्यकता है, तो बस का उपयोग करें [NSOrderedSet orderedSetWithArray:array];आप पहले के बजाय एक सरणी के माध्यम से वापस प्राप्त कर सकते हैं array = [orderedSet allObjects];या केवल NSOrderedSetएस का उपयोग कर सकते हैं NSArray
Regexident

10
@ Regexident का समाधान आदर्श है। बस [orderedSet allObjects]साथ बदलने की जरूरत है [orderedSet array]!
inket

नाइस वन;) मुझे उत्तर पसंद है जो डेवलपर को बहुत सारे संशोधनों के बिना कॉपी और पेस्ट बनाता है, यह उत्तर है कि हर डेवलपर डेवलपर पसंद करेगा;) @ abo3atef
Abo3atef

धन्यवाद, लेकिन आपको अपने उदाहरण को ठीक करना चाहिए। कारण - हम आमतौर पर है NSArrayऔर अस्थायी बनाना चाहिए NSMutableArray। अपने उदाहरण में आप इसके विपरीत काम करते हैं
व्याचेस्लाव गेर्चिकोव

किसी को पता है कि डुप्लिकेट को हटाने के लिए कौन सा सबसे अच्छा दृश्य है यह तरीका (उपयोग करना NSSet) या @Simon Whitaker लिंक है जो डुप्लिकेट मान को जोड़ने से पहले रोकता है जो कुशल तरीका है?
मत्ती अरसन

78

मुझे पता है कि यह एक पुराना सवाल है, लेकिन NSArray यदि आप ऑर्डर के बारे में परवाह नहीं करते हैं, तो डुप्लिकेट को हटाने का एक और सुंदर तरीका है ।

यदि हम कुंजी संचालक कोडिंग से ऑब्जेक्ट ऑपरेटर्स का उपयोग करते हैं तो हम यह कर सकते हैं:

uniquearray = [yourarray valueForKeyPath:@"@distinctUnionOfObjects.self"];

जैसा कि एंथोपक ने भी उल्लेख किया है कि संपत्ति के आधार पर डुप्लिकेट को निकालना संभव है। एक उदाहरण होगा:@distinctUnionOfObjects.name


3
हाँ, यह वही है जो मैं भी उपयोग करता हूं! यह एक बहुत ही शक्तिशाली दृष्टिकोण है, जो बहुत सारे आईओएस डेवलपर्स को नहीं पता है!
लेफ्टिस

1
मुझे आश्चर्य हुआ जब मैंने सीखा कि यह संभव हो सकता है। मैंने सोचा था कि कई आईओएस डेवलपर्स यह नहीं जान सके कि मैंने इस जवाब को जोड़ने का फैसला क्यों किया है :)
टियागो अल्मेडा

12
यह वस्तुओं के क्रम को बनाए नहीं रखता है।
रुडोल्फ एडमकोविच

2
हाँ, यह आदेश को तोड़ता है।
रोस्टीस्लाव ड्रूज़चेन्को जूल

ध्यान दें कि इसका उपयोग @distinctUnionOfObjects.propertyकस्टम ऑब्जेक्ट्स की एक सरणी की संपत्ति द्वारा डुप्लिकेट को निकालने के लिए भी किया जा सकता है । उदाहरण के लिए@distinctUnionOfObjects.name
एंथोपक

47

हां, NSSet का उपयोग करना एक समझदार दृष्टिकोण है।

जिम पल्स के जवाब में जोड़ने के लिए, यहां ऑर्डर को बनाए रखते हुए डुप्लिकेट को अलग करने का एक वैकल्पिक तरीका है:

// Initialise a new, empty mutable array 
NSMutableArray *unique = [NSMutableArray array];

for (id obj in originalArray) {
    if (![unique containsObject:obj]) {
        [unique addObject:obj];
    }
}

यह मूल रूप से जिम के रूप में एक ही दृष्टिकोण है, लेकिन मूल से डुप्लिकेट को हटाने के बजाय एक ताजा म्यूटेबल सरणी में अद्वितीय वस्तुओं को कॉपी करता है। यह एक बहुत बड़ी सरणी के मामले में कुछ डुप्लिकेट के साथ बहुत अधिक स्मृति को कुशल बनाता है (संपूर्ण सरणी की प्रतिलिपि बनाने की कोई आवश्यकता नहीं है), और मेरी राय में थोड़ा अधिक पठनीय है।

ध्यान दें कि किसी भी मामले में, यह देखने के लिए कि क्या कोई वस्तु पहले से ही लक्ष्य सरणी में शामिल है ( containsObject:मेरे उदाहरण में, या indexOfObject:inRange:जिम में) बड़े सरणियों के लिए अच्छी तरह से स्केल नहीं करता है। वे चेक ओ (एन) समय में चलते हैं, जिसका अर्थ है कि यदि आप मूल सरणी के आकार को दोगुना करते हैं तो प्रत्येक चेक को चलने में दोगुना समय लगेगा। जब से आप सरणी में प्रत्येक ऑब्जेक्ट के लिए चेक कर रहे हैं, तो आप उन अधिक महंगी चेक को भी चला रहे होंगे। समग्र एल्गोरिथ्म (मेरा और जिम दोनों) ओ (एन 2 ) समय में चलता है , जो मूल सरणी बढ़ने के साथ जल्दी महंगा हो जाता है।

उस डाउन टू ओ (एन) समय को प्राप्त करने के लिए आप NSMutableSetनए एरे में पहले से जोड़े गए आइटमों के रिकॉर्ड को स्टोर करने के लिए उपयोग कर सकते हैं , क्योंकि एनएसएसईटी लुकअप ओ (एन) के बजाय ओ (1) हैं। दूसरे शब्दों में, यह देखने के लिए कि क्या कोई तत्व NSSet का सदस्य है, सेट में कितने तत्व हैं, इसकी परवाह किए बिना एक ही समय लगता है।

इस दृष्टिकोण का उपयोग कर कोड कुछ इस तरह दिखाई देगा:

NSMutableArray *unique = [NSMutableArray array];
NSMutableSet *seen = [NSMutableSet set];

for (id obj in originalArray) {
    if (![seen containsObject:obj]) {
        [unique addObject:obj];
        [seen addObject:obj];
    }
}

यह अभी भी थोड़ा बेकार लगता है; हम अभी भी एक नई व्यूह रचना कर रहे हैं, जब प्रश्न स्पष्ट हो गया है कि मूल सारणी उत्परिवर्तनीय है, इसलिए हमें इसे जगह पर डी-डुबाने में सक्षम होना चाहिए और कुछ मेमोरी को सहेजना चाहिए। कुछ इस तरह:

NSMutableSet *seen = [NSMutableSet set];
NSUInteger i = 0;

while (i < [originalArray count]) {
    id obj = [originalArray objectAtIndex:i];

    if ([seen containsObject:obj]) {
        [originalArray removeObjectAtIndex:i];
        // NB: we *don't* increment i here; since
        // we've removed the object previously at
        // index i, [originalArray objectAtIndex:i]
        // now points to the next object in the array.
    } else {
        [seen addObject:obj];
        i++;
    }
}

अद्यतन : यूरी नियाज़ोव ने बताया कि मेरा अंतिम उत्तर वास्तव में ओ (एन 2 ) removeObjectAtIndex:में चलता है क्योंकि शायद ओ (एन) समय में चलता है।

(वे कहते हैं "शायद" क्योंकि हम यह सुनिश्चित करने के लिए नहीं जानते हैं कि यह कैसे लागू किया जाता है, लेकिन एक संभव कार्यान्वयन यह है कि ऑब्जेक्ट को इंडेक्स एक्स पर हटाने के बाद विधि फिर एरे में एक्स + 1 से आखिरी ऑब्जेक्ट तक हर तत्व से गुजरती है। , उन्हें पिछले सूचकांक में ले जाना। यदि ऐसा है तो वास्तव में O (N) प्रदर्शन है।)

इसलिए क्या करना है? यह स्थिति पर निर्भर करता है। यदि आपको एक बड़ा सरणी मिला है और आप केवल बहुत सारे डुप्लिकेट की उम्मीद कर रहे हैं तो इन-प्लेस डे-डुप्लीकेशन ठीक काम करेगा और आपको डुप्लिकेट सरणी बनाने के लिए बचाएगा। यदि आपको एक ऐसा सरणी मिला है जहाँ आप बहुत सारे डुप्लिकेट की उम्मीद कर रहे हैं तो एक अलग, डी-डुप्ड सरणी का निर्माण करना संभवतः सबसे अच्छा तरीका है। यहाँ ले दूर यह है कि बड़ा- O अंकन केवल एक एल्गोरिथ्म की विशेषताओं का वर्णन करता है, यह आपको निश्चित रूप से नहीं बताएगा जो किसी भी परिस्थिति के लिए सबसे अच्छा है।


20

यदि आप iOS 5+ (संपूर्ण iOS दुनिया को कवर करता है) को लक्षित कर रहे हैं, तो सबसे अच्छा उपयोग करें NSOrderedSet। यह डुप्लिकेट को हटाता है और आपके आदेश को बनाए रखता है NSArray

बस करो

NSOrderedSet *orderedSet = [NSOrderedSet orderedSetWithArray:yourArray];

अब आप इसे एक अद्वितीय NSArray में बदल सकते हैं

NSArray *uniqueArray = orderedSet.array;

या सिर्फ ऑर्डरसेट का उपयोग करें क्योंकि इसमें NSArray की तरह ही तरीके हैं objectAtIndex:, firstObjectऔर इसी तरह।

जिस containsपर NSOrderedSetयह होगा उस पर सदस्यता की जांच और भी तेज हैNSArray

अधिक चेकआउट के लिए NSOrderedSet Reference


यह मेरा वोट मिला, मैंने उन सभी को पढ़ा और यह सबसे अच्छा जवाब है। विश्वास नहीं कर सकता शीर्ष उत्तर एक मैनुअल लूप है। ओह, उन्होंने अब इस जवाब की नकल की है।
मल्हल

19

OS X v10.7 और बाद में उपलब्ध है।

यदि आप आदेश के बारे में चिंतित हैं, तो करने का सही तरीका

NSArray *no = [[NSOrderedSet orderedSetWithArray:originalArray]allObjects];

यहाँ आदेश में NSArray से डुप्लिकेट मानों को हटाने का कोड है।


1
allObjects सरणी होना चाहिए
malhal

7

आदेश की आवश्यकता है

NSArray *yourarray = @[@"a",@"b",@"c"];
NSOrderedSet *orderedSet = [NSOrderedSet orderedSetWithArray:yourarray];
NSArray *arrayWithoutDuplicates = [orderedSet array];
NSLog(@"%@",arrayWithoutDuplicates);

या आदेश की जरूरत नहीं है

NSSet *set = [NSSet setWithArray:yourarray];
NSArray *arrayWithoutOrder = [set allObjects];
NSLog(@"%@",arrayWithoutOrder);

3

यहाँ मैंने मुख्य नाम से डुप्लिकेट नाम मान हटा दिए और NSMutableArray (listOfUsers) में स्टोर परिणाम

for (int i=0; i<mainArray.count; i++) {
    if (listOfUsers.count==0) {
        [listOfUsers addObject:[mainArray objectAtIndex:i]];

    }
   else if ([[listOfUsers valueForKey:@"name" ] containsObject:[[mainArray objectAtIndex:i] valueForKey:@"name"]])
    {  
       NSLog(@"Same object");
    }
    else
    {
        [listOfUsers addObject:[mainArray objectAtIndex:i]];
    }
}

1

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

// sortedSourceArray is the source array, already sorted
NSMutableArray *newArray = [[NSMutableArray alloc] initWithObjects:[sortedSourceArray objectAtIndex:0]];
for (int i = 1; i < [sortedSourceArray count]; i++)
{
    if (![[sortedSourceArray objectAtIndex:i] isEqualToString:[sortedSourceArray objectAtIndex:(i-1)]])
    {
        [newArray addObject:[tempArray objectAtIndex:i]];
    }
}

यह उन NSOrderedSetउत्तरों की तरह दिखता है जिनके सुझाव भी बहुत कम कोड की आवश्यकता होती है, लेकिन यदि आप NSOrderedSetकिसी कारण से उपयोग नहीं कर सकते हैं , और आपके पास एक क्रमबद्ध सरणी है, तो मुझे विश्वास है कि मेरा समाधान सबसे तेज़ होगा। मुझे यकीन नहीं है कि यह कैसे NSOrderedSetसमाधान की गति के साथ तुलना करता है। यह भी ध्यान दें कि मेरा कोड के साथ जाँच कर रहा है isEqualToString:, इसलिए अक्षरों की एक ही श्रृंखला एक से अधिक बार दिखाई नहीं देगी newArray। मुझे यकीन नहीं है कि NSOrderedSetसमाधान मूल्य के आधार पर या स्मृति स्थान के आधार पर डुप्लिकेट को हटा देगा।

मेरा उदाहरण मानता है कि sortedSourceArrayसिर्फ NSStringएस, सिर्फ NSMutableStringएस या दोनों का मिश्रण है। अगर sortedSourceArrayइसके बजाय सिर्फ NSNumbers या सिर्फ NSDates है, तो आप प्रतिस्थापित कर सकते हैं

if (![[sortedSourceArray objectAtIndex:i] isEqualToString:[sortedSourceArray objectAtIndex:(i-1)]])

साथ में

if ([[sortedSourceArray objectAtIndex:i] compare:[sortedSourceArray objectAtIndex:(i-1)]] != NSOrderedSame)

और इसे पूरी तरह से काम करना चाहिए। यदि sortedSourceArrayइसमें NSStrings, NSNumbers और / या NSDates का मिश्रण है, तो यह संभवतः दुर्घटनाग्रस्त हो जाएगा।



1

एक और सरल तरीका है जिसे आप आज़मा सकते हैं, जो सरणी में ऑब्जेक्ट जोड़ने से पहले डुप्लिकेट मान नहीं जोड़ेंगे: -

// मान लें कि mutableArray आवंटित किया गया है और प्रारंभिक है और इसमें कुछ मूल्य हैं

if (![yourMutableArray containsObject:someValue])
{
   [yourMutableArray addObject:someValue];
}

1

उद्देश्य-सी में NSMutableArray से डुप्लिकेट मान निकालें

NSMutableArray *datelistArray = [[NSMutableArray alloc]init];
for (Student * data in fetchStudentDateArray)
{
    if([datelistArray indexOfObject:data.date] == NSNotFound)
    [datelistArray addObject:data.date];
}

0

यहाँ NSMutable Array से डुप्लिकेट मानों को हटाने का कोड है। यह आपके लिए काम करेगा। myArray आपका Mutable Array है जिसे आप डुप्लिकेट मानों को हटाना चाहते हैं।

for(int j = 0; j < [myMutableArray count]; j++){
    for( k = j+1;k < [myMutableArray count];k++){
    NSString *str1 = [myMutableArray objectAtIndex:j];
    NSString *str2 = [myMutableArray objectAtIndex:k];
    if([str1 isEqualToString:str2])
        [myMutableArray removeObjectAtIndex:k];
    }
 } // Now print your array and will see there is no repeated value

0

का उपयोग Orderedsetकर चाल होगा। यह हटाए गए डुप्लिकेट को सरणी से रखेगा और ऑर्डर बनाए रखेगा जो सामान्य रूप से सेट नहीं करता है


-3

बस इस सरल कोड का उपयोग करें:

NSArray *hasDuplicates = /* (...) */;
NSArray *noDuplicates = [[NSSet setWithArray: hasDuplicates] allObjects];

चूंकि nsset डुप्लिकेट मानों की अनुमति नहीं देता है और सभी ऑब्जेक्ट एक सरणी देता है


मेरे लिए काम किया। आपको बस इतना करना है कि आप अपने NSArray को फिर से छांट रहे हैं क्योंकि NSSet एक बिना बदले NSArray देता है।
lindinax

या बस का उपयोग NSOrderedSetकी insteed NSSet
10
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.