পুনরাবৃত্তির সময় এনএসমিটেবলআরে থেকে সরানোর সর্বোত্তম উপায়?


194

কোকোয়, যদি আমি কোনও এনএসমিটেবলআরির মধ্য দিয়ে লুপ করতে এবং নির্দিষ্ট মানদণ্ডের সাথে মানানসই একাধিক অবজেক্টগুলি সরাতে চাই, তবে প্রতিবার কোনও বস্তু সরালে লুপটি পুনরায় চালু না করে এটি করার সর্বোত্তম উপায় কী?

ধন্যবাদ,

সম্পাদনা করুন: কেবল স্পষ্ট করে বলার জন্য - আমি সবচেয়ে ভাল উপায় খুঁজছিলাম, উদাহরণস্বরূপ আমি যে সূচকটি করছি সেটিকে ম্যানুয়ালি আপডেট করার চেয়ে আরও মার্জিত কিছু। উদাহরণস্বরূপ সি ++ এ আমি করতে পারি;

iterator it = someList.begin();

while (it != someList.end())
{
    if (shouldRemove(it))   
        it = someList.erase(it);
}

9
পিছন থেকে সামনের দিকে লুপ করুন।
হট লিকস

কেউ "কেন" উত্তর দেয় না
onwayway133

1
@ হটলিক্স আমার সর্বকালের সবচেয়ে প্রিয় এবং প্রোগ্রামিংয়ের সবচেয়ে কম মূল্যায়ন সমাধান: ডি
জুলিয়ান এফ। ওয়েইনার্ট

উত্তর:


388

স্পষ্টতার জন্য আমি একটি প্রাথমিক লুপ তৈরি করতে চাই যেখানে আমি মুছতে আইটেমগুলি সংগ্রহ করি। তারপরে আমি সেগুলি মুছব। অবজেক্টিভ-সি 2.0 সিনট্যাক্স ব্যবহার করে এখানে একটি নমুনা দেওয়া হয়েছে:

NSMutableArray *discardedItems = [NSMutableArray array];

for (SomeObjectClass *item in originalArrayOfItems) {
    if ([item shouldBeDiscarded])
        [discardedItems addObject:item];
}

[originalArrayOfItems removeObjectsInArray:discardedItems];

তারপরে সূচকগুলি সঠিকভাবে আপডেট হচ্ছে কিনা, বা অন্যান্য সামান্য বুককিপিংয়ের বিশদ সম্পর্কিত কোনও প্রশ্ন নেই।

যুক্ত করতে সম্পাদিত:

অন্য উত্তরে এটি উল্লিখিত হয়েছে যে বিপরীতমুখী গঠন দ্রুত হওয়া উচিত। অর্থ্যাৎ যদি আপনি অ্যারের মাধ্যমে পুনরাবৃত্তি করেন এবং অবজেক্টগুলি ফেলে দেওয়ার পরিবর্তে রাখার জন্য অবজেক্টের নতুন অ্যারে রচনা করেন। এটি সত্য হতে পারে (যদিও নতুন অ্যারে বরাদ্দের মেমরি এবং প্রসেসিং ব্যয় সম্পর্কে কী বলা যায়, এবং পুরানোটি বাতিল করে দেওয়া হয়?) তবে এটি দ্রুততর হলেও এটি নির্দোষ বাস্তবায়নের জন্য এত বড় চুক্তি নাও হতে পারে, কারণ এনএসআরাই "সাধারণ" অ্যারের মতো আচরণ করবেন না। তারা কথা বলে তবে তারা আলাদা হাঁটাচলা করে। এখানে একটি ভাল বিশ্লেষণ দেখুন:

বিপরীতমুখী সূত্রটি দ্রুততর হতে পারে তবে এটি কিনা সেদিকে আমার কখনই নজর দেওয়ার প্রয়োজন নেই কারণ উপরের সূত্রটি আমার প্রয়োজনের জন্য সর্বদা যথেষ্ট দ্রুত ছিল।

আমার কাছে টোক-হোম বার্তাটি হ'ল যেই সূত্রটি আপনার কাছে পরিষ্কার use প্রয়োজন হলেই অনুকূলিত করুন। আমি ব্যক্তিগতভাবে উপরের সূত্রটি সবচেয়ে পরিষ্কার দেখতে পেয়েছি, যে কারণে আমি এটি ব্যবহার করি। তবে যদি বিপরীত সূত্রটি আপনার কাছে আরও পরিষ্কার হয় তবে এটির জন্য যান।


47
সাবধান হন যে বস্তুগুলি একবারে একাধিকবার অ্যারেতে থাকলে এটি বাগগুলি তৈরি করতে পারে। বিকল্প হিসাবে আপনি একটি NSMutableIndexSet এবং - (শূন্য) অপসারণঅবজেক্টসআইটেক্সেক্স ব্যবহার করতে পারেন।
জর্জি স্কলি

1
বিপরীতটি করা আসলে এটি দ্রুত is পারফরম্যান্সের পার্থক্যটি বেশ বিশাল, তবে যদি আপনার অ্যারেটি এত বড় না হয় তবে সময়গুলি উভয় উপায়েই তুচ্ছ হতে চলেছে।
ব্যবহারকারী 1032657

আমি বিপরীতগুলি ব্যবহার করেছিলাম ... অ্যারেটিকে শূন্য হিসাবে তৈরি করেছিলাম ... তবে আমি যা চেয়েছিলাম তা যুক্ত করে ডেটা পুনরায় লোড করলাম ... সম্পন্ন ... ডামিআরে তৈরি করেছে যা মূল অ্যারের মিরর যাতে আমাদের আসল ডেটা থাকে
ফাহিম পার্কার

বিপরীতে করতে অতিরিক্ত মেমরি বরাদ্দ করা দরকার। এটি কোনও স্থানের অ্যালগরিদম নয় এবং কিছু ক্ষেত্রে ভাল ধারণাও নয়। আপনি সরাসরি অপসারণ করার পরে আপনি কেবল অ্যারেটি স্থানান্তর করবেন (এটি অত্যন্ত দক্ষ যেহেতু এটি একে একে সরবে না, এটি একটি বড় অংশটি স্থানান্তর করতে পারে) তবে আপনি যখন নতুন অ্যারে তৈরি করেন তখন আপনার সমস্ত বরাদ্দ এবং অ্যাসাইনমেন্টের প্রয়োজন হয় need সুতরাং আপনি যদি কেবল কয়েকটি আইটেম মুছেন তবে বিপরীতমুখীটি অনেক ধীর হবে। এটি একটি সাধারণ মনে হচ্ছে ডান অ্যালগরিদম।
জ্যাক

82

আরও একটি প্রকরণ। সুতরাং আপনি পঠনযোগ্যতা এবং ভাল অভিনয় পাবেন:

NSMutableIndexSet *discardedItems = [NSMutableIndexSet indexSet];
SomeObjectClass *item;
NSUInteger index = 0;

for (item in originalArrayOfItems) {
    if ([item shouldBeDiscarded])
        [discardedItems addIndex:index];
    index++;
}

[originalArrayOfItems removeObjectsAtIndexes:discardedItems];

এটা সত্যিই দারুন. আমি অ্যারে থেকে একাধিক আইটেম সরানোর চেষ্টা করছিলাম এবং এটি পুরোপুরি কার্যকর হয়েছিল। অন্যান্য পদ্ধতি সমস্যা সৃষ্টি করছিল :) ধন্যবাদ মানুষ
অভিনবভিনয়

কোরি, এই উত্তরটি (নীচে) বলেছে যে, removeObjectsAtIndexesজিনিসগুলি অপসারণের সবচেয়ে খারাপ পদ্ধতি, আপনি কি এর সাথে একমত? আমি এটি জিজ্ঞাসা করছি কারণ আপনার উত্তর এখন খুব পুরানো। তবুও সেরাটি বেছে নেওয়া ভাল?
হেমাং

পাঠযোগ্যতার দিক থেকে আমি এই সমাধানটি খুব পছন্দ করি। @ হটলিক্স উত্তরের সাথে তুলনা করলে এটি পারফরম্যান্সের দিক থেকে কীভাবে?
ভিক্টর মিয়া আলদেকিয়া

ওবজে-সি-তে অ্যারে থেকে অবজেক্টগুলি মুছে ফেলার সময় এই পদ্ধতিটিকে অবশ্যই উত্সাহ দেওয়া উচিত।
বোরিয়াস

enumerateObjectsUsingBlock:আপনি বিনামূল্যে ইনডেক্স বৃদ্ধি পাবেন।
পেকম্ব

42

এটি খুব সাধারণ সমস্যা। আপনি কেবল পিছনের দিকে পুনরাবৃত্তি করুন:

for (NSInteger i = array.count - 1; i >= 0; i--) {
   ElementType* element = array[i];
   if ([element shouldBeRemoved]) {
       [array removeObjectAtIndex:i];
   }
}

এটি একটি খুব সাধারণ প্যাটার্ন।


জেনস উত্তরটি মিস করত, কারণ সে কোডটি লিখে ফেলত না: পি .. থ্যাঙ্কস
এম

3
এটি সেরা পদ্ধতি। মনে রাখা গুরুত্বপূর্ণ যে পুনরাবৃত্তির পরিবর্তনশীলটি একটি স্বাক্ষরিত হওয়া উচিত, যদিও অবজেক্টিভ-সি-তে অ্যারে সূচকগুলি স্বাক্ষরবিহীন হিসাবে ঘোষিত হয়েছে (আমি বুঝতে পারি যে অ্যাপল কীভাবে এখন আফসোস করে))
মোজুবা

39

অন্যান্য উত্তরগুলির মধ্যে কিছুতে খুব বড় অ্যারেগুলিতে দুর্বল পারফরম্যান্স হবে, কারণ পদ্ধতিগুলি গ্রহণকারীকে রৈখিক অনুসন্ধান করতে পছন্দ করে removeObject:এবং removeObjectsInArray:এটি জঞ্জাল, কারণ আপনি ইতিমধ্যে জানেন যে অবজেক্টটি কোথায়। এছাড়াও, যে কোনও কল করতে removeObjectAtIndex:সূচি থেকে অ্যারের শেষ পর্যন্ত মূল্যগুলি অনুলিপি করতে হবে একবারে এক স্লটে।

আরও দক্ষ নিম্নলিখিত হবে:

NSMutableArray *array = ...
NSMutableArray *itemsToKeep = [NSMutableArray arrayWithCapacity:[array count]];
for (id object in array) {
    if (! shouldRemove(object)) {
        [itemsToKeep addObject:object];
    }
}
[array setArray:itemsToKeep];

যেহেতু আমরা এর সক্ষমতা নির্ধারণ করেছি itemsToKeep, আমরা পুনরায় আকার দেওয়ার সময় মানগুলি অনুলিপি করতে কোনও সময় নষ্ট করি না। আমরা স্থানে অ্যারেটি সংশোধন করি না, তাই আমরা দ্রুত গণনা ব্যবহার করতে মুক্ত। ব্যবহার setArray:সামগ্রীগুলি প্রতিস্থাপন করতে arrayসঙ্গে itemsToKeepদক্ষ হবে। আপনার কোডের উপর নির্ভর করে আপনি এমনকি শেষ লাইনটি প্রতিস্থাপন করতে পারেন:

[array release];
array = [itemsToKeep retain];

সুতরাং মানগুলি অনুলিপি করার প্রয়োজন নেই, কেবলমাত্র একটি পয়েন্টার অদলবদল করুন।


সময়ের জটিলতার ক্ষেত্রে এই অ্যালগো ভাল প্রমাণিত হয়। আমি স্থান জটিলতার নিরিখে এটি বোঝার চেষ্টা করছি am আমার বাস্তবায়ন প্রায় একই জায়গায় ঘুরছে যেখানে আমি আসল 'অ্যারে গণনা'র সাথে আইটেমসটোকিপ'র সক্ষমতা নির্ধারণ করেছি। তবে বলুন আমি অ্যারে থেকে কয়েকটি বস্তু চাই না তাই আমি এটি আইটেম টোককিপে যুক্ত করব না। সুতরাং আমার আইটেম টোককিপের সেই ক্ষমতাটি 10, তবে আমি এটিতে কেবলমাত্র 6 টি বস্তু সঞ্চয় করি। এর অর্থ কি আমি 4 টি বস্তুর স্থান নষ্ট করছি? পিএস ত্রুটিগুলি খুঁজে পাচ্ছে না, কেবল আলগো জটিলতা বোঝার চেষ্টা করছে। :)
প্রযুক্তি_হুমান

হ্যাঁ, আপনি যে চারটি পয়েন্টার ব্যবহার করছেন না তার জন্য আপনার কাছে জায়গা সংরক্ষিত আছে। অ্যারে মনে রাখবেন কেবল পয়েন্টার রয়েছে, বস্তুগুলি নিজেরাই নয়, সুতরাং চারটি অবজেক্টের জন্য যার অর্থ 16 বাইট (32 বিট আর্কিটেকচার) বা 32 বাইট (64 বিট)।
বেনজাদো

নোট করুন যে কোনও সমাধানের জন্য সর্বোত্তমভাবে 0 টি অতিরিক্ত স্থান প্রয়োজন (আপনি জায়গাটিতে আইটেমগুলি মুছুন) বা খারাপ অ্যারে মূল অ্যারের আকারের দ্বিগুণ (কারণ আপনি অ্যারের একটি অনুলিপি তৈরি করেছেন)। আবার, কারণ আমরা পয়েন্টারগুলির সাথে কাজ করছি এবং সামগ্রীর অনুলিপিগুলি নেই, বেশিরভাগ পরিস্থিতিতে এটি বেশ সস্তা।
বেনজাদো

আচ্ছা আমি বুঝে গেছি. ধন্যবাদ বেনজাদো !!
টেক_মানুষ

এই পোস্ট অনুসারে , অ্যারেরের ইঙ্গিতটি উইথ ক্যাপাসিটি: অ্যারের আকার সম্পর্কে পদ্ধতিটি আসলে ব্যবহার হচ্ছে না।
ক্রেম্ক

28

আপনার পরিবর্তনীয় অ্যারে থেকে আইটেমগুলি সরাতে আপনি এনএসপ্রেডিকেট ব্যবহার করতে পারেন। এর জন্য লুপের জন্য কোনও দরকার নেই।

উদাহরণস্বরূপ, যদি আপনার নামের একটি এনএস পরিবর্তনযোগ্যআরে থাকে তবে আপনি এটির মতো একটি প্রিকিকেট তৈরি করতে পারেন:

NSPredicate *caseInsensitiveBNames = 
[NSPredicate predicateWithFormat:@"SELF beginswith[c] 'b'"];

নিম্নলিখিত লাইনটি আপনাকে এমন একটি অ্যারের সাথে ছেড়ে দেবে যার সাথে খ দিয়ে শুরু হওয়া নামগুলি রয়েছে।

[namesArray filterUsingPredicate:caseInsensitiveBNames];

আপনার যদি প্রয়োজন পূর্বাভাস তৈরি করতে সমস্যা হয় তবে এই অ্যাপল বিকাশকারী লিঙ্কটি ব্যবহার করুন


3
লুপগুলির জন্য কোনও দৃশ্যমান প্রয়োজন । ফিল্টার অপারেশনে একটি লুপ রয়েছে, আপনি কেবল এটি দেখতে পাচ্ছেন না।
হট লিক্স

18

আমি 4 বিভিন্ন পদ্ধতি ব্যবহার করে একটি পারফরম্যান্স পরীক্ষা করেছি। প্রতিটি পরীক্ষা 100,000 উপাদান অ্যারেতে সমস্ত উপাদানগুলির মাধ্যমে পুনরাবৃত্তি করে এবং প্রতিটি 5 তম আইটেম সরানো হয়। অপ্টিমাইজেশন / ছাড়াই ফলাফলগুলি খুব বেশি পৃথক হয়নি। এগুলি আইপ্যাড 4 এ করা হয়েছিল:

(1) removeObjectAtIndex:- 271 এমএস

(2) removeObjectsAtIndexes:- 1010 এমএস (কারণ সূচী সেটটি তৈরি করতে ~ 700 এমএস লাগে; অন্যথায় এটি মূলত রিমোটঅজেক্টএটিএন্ডেক্স কল করার অনুরূপ: প্রতিটি আইটেমের জন্য)

(3) removeObjects:- 326 এমএস

(4) পরীক্ষায় উত্তীর্ণ বস্তুগুলি সহ একটি নতুন অ্যারে তৈরি করুন - 17 এমএস

সুতরাং, একটি নতুন অ্যারে তৈরি করা এখন পর্যন্ত দ্রুততম। অপসারণ পদ্ধতিগুলি অপসারণের ব্যতীত অন্যান্য প্রকল্পগুলি তুলনীয়, সূচক সেটটি তৈরি করার জন্য প্রয়োজনীয় সময়ের কারণে, অপসারণের জন্য আরও আইটেমগুলির সাথে আরও খারাপ হবে।


1
আপনি একটি নতুন অ্যারে তৈরি করার সময়টি গণনা করেছেন এবং এটির পরে ডিঅলোকেট করেছেন। আমি বিশ্বাস করি না এটি 17 এমএসে এটি একা করতে পারে। প্লাস 75,000 এসাইনমেন্ট?
জ্যাক

একটি নতুন অ্যারে তৈরি করতে এবং
অপসারণের জন্য প্রয়োজনীয় সময়টি

আপনি সম্ভবত বিপরীত লুপ স্কিমটি পরিমাপ করেন নি।
হট লিক্স

প্রথম পরীক্ষাটি বিপরীত লুপ স্কিমের সমতুল্য।
ব্যবহারকারী 1032657

যখন আপনি আপনার নতুন অ্যারে ছেড়ে চলে যান, এবং আপনার প্রভাররে নুল্ড হয় তখন কী হয়? পূর্বআর্রে নামকরণ করা হয়েছে (বা এর নাম পরিবর্তন করুন) এর জন্য আপনাকে নতুন অ্যারেটি অনুলিপি করতে হবে অন্যথায় কীভাবে আপনার অন্যান্য কোড এটি উল্লেখ করবে?
aremvee

17

হয় সূচকগুলি ধরে লুপ গণনা ব্যবহার করুন:

for (NSInteger i = array.count - 1; i >= 0; --i) {

অথবা আপনি যে জিনিসগুলি রাখতে চান তা দিয়ে একটি অনুলিপি তৈরি করুন।

বিশেষত, একটি for (id object in array)লুপ বা ব্যবহার করবেন না NSEnumerator


3
আপনার উত্তরটি m8 কোডে লিখতে হবে। হা হা এটা প্রায় মিস।
ফ্লোইউআই সরলইউইস্টেস্টিং ডটকম

এটা সঠিক না. "for (অ্যারে আইডি অবজেক্ট)" "for (NSInteger i = array.count - 1; i> = 0; --i)" এর চেয়ে দ্রুততর এবং দ্রুত পুনরাবৃত্তি বলে। পুনরুক্তি ব্যবহার করা অবশ্যই সূচকের চেয়ে দ্রুত।
জ্যাক

@ জ্যাক - তবে যদি আপনি কোনও পুনরুক্তির অধীনে কোনও উপাদান সরিয়ে ফেলেন তবে আপনি সাধারণত সর্বনাশ তৈরি করেন। (এবং "দ্রুত পুনরাবৃত্তি" সবসময় তত দ্রুত হয় না))
হট লিকস

উত্তরটি ২০০৮ সালের। দ্রুত পুনরাবৃত্তির অস্তিত্ব ছিল না।
জেনস অ্যাটন

12

আইওএস 4+ বা ওএস এক্স 10.6+ এর জন্য অ্যাপল এপিআইয়ের মতো passingTestসিরিজ যুক্ত করেছে । যেমন এপিআই সহ একটি সমাধান হবে:NSMutableArray– indexesOfObjectsPassingTest:

NSIndexSet *indexesToBeRemoved = [someList indexesOfObjectsPassingTest:
    ^BOOL(id obj, NSUInteger idx, BOOL *stop) {
    return [self shouldRemove:obj];
}];
[someList removeObjectsAtIndexes:indexesToBeRemoved];

12

আজকাল আপনি বিপরীত ব্লক-ভিত্তিক গণনা ব্যবহার করতে পারেন। একটি সাধারণ উদাহরণ কোড:

NSMutableArray *array = [@[@{@"name": @"a", @"shouldDelete": @(YES)},
                           @{@"name": @"b", @"shouldDelete": @(NO)},
                           @{@"name": @"c", @"shouldDelete": @(YES)},
                           @{@"name": @"d", @"shouldDelete": @(NO)}] mutableCopy];

[array enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
    if([obj[@"shouldDelete"] boolValue])
        [array removeObjectAtIndex:idx];
}];

ফলাফল:

(
    {
        name = b;
        shouldDelete = 0;
    },
    {
        name = d;
        shouldDelete = 0;
    }
)

কোডের এক লাইনের সাথে অন্য একটি বিকল্প:

[array filterUsingPredicate:[NSPredicate predicateWithFormat:@"shouldDelete == NO"]];

অ্যারে পুনরায় স্থানান্তরিত হবে না এমন কোন গ্যারান্টি আছে?
সিএফআর

পুনঃনির্ধারণের অর্থ কী?
ভাইকিংগুন্ডো

রৈখিক কাঠামো থেকে উপাদান অপসারণ করার সময় এটি সম্ভবত নতুন স্বতন্ত্র মেমরি ব্লক বরাদ্দ করা এবং সেখানে সমস্ত উপাদান সরিয়ে নেওয়া কার্যকর। এই ক্ষেত্রে সমস্ত পয়েন্টার অবৈধ হবে।
সিএফআর

মুছে ফেলা অপারেশনটি শেষ পর্যন্ত কতগুলি উপাদান মুছে ফেলা হবে তা জানতে পারে না, এটি অপসারণের সময় এটি করার কোনও মানে হয় না। যাইহোক: বাস্তবায়ন বিশদ, যুক্তিসঙ্গত কোড লিখতে আপেলকে বিশ্বাস করতে হবে।
ভাইকিংগুন্ডো

প্রথমটি সুন্দর নয় (কারণ এটি প্রথম স্থানে কীভাবে কাজ করে সে সম্পর্কে আপনাকে অনেক কিছু চিন্তা করতে হবে) এবং দ্বিতীয়টি নিরাপদ রিফ্যাক্টরিং নয়। সুতরাং শেষ পর্যন্ত আমি ক্লাসিক গৃহীত সমাধানের সাথে শেষ করেছি যা আসলে বেশ পাঠযোগ্য।
রিনিটিক

8

আরও ঘোষিত উপায়ে আইটেমগুলির সাথে মেলে এমন মানদণ্ডের উপর নির্ভর করে আপনি অপসারণ করতে পারবেন:

[theArray filterUsingPredicate:aPredicate]

@ নাথান খুব দক্ষ হতে হবে


6

এখানে সহজ এবং পরিষ্কার উপায়। আমি দ্রুত গণনা কলটিতে আমার অ্যারে ডুপ্লিকেট করতে চাই:

for (LineItem *item in [NSArray arrayWithArray:self.lineItems]) 
{
    if ([item.toBeRemoved boolValue] == YES) 
    {
        [self.lineItems removeObject:item];
    }
}

এইভাবে আপনি অ্যারের অনুলিপিটি মুছে ফেলা হচ্ছে, উভয় একই জিনিসকে ধারণ করে তার মাধ্যমে গণনা করবেন। একটি এনএসআরারি কেবলমাত্র অবজেক্ট পয়েন্টার ধরে থাকে তাই এটি সম্পূর্ণ সূক্ষ্ম মেমরি / পারফরম্যান্স বুদ্ধিমান।


2
বা এমন কি সহজ -for (LineItem *item in self.lineItems.copy)
আলেক্সান্ডার জি

5

আপনি যে বস্তুগুলি সরাতে চান সেটি দ্বিতীয় অ্যারেতে যুক্ত করুন এবং লুপের পরে -reoveovebjectsInArray: ব্যবহার করুন।


5

এটি করা উচিত:

    NSMutableArray* myArray = ....;

    int i;
    for(i=0; i<[myArray count]; i++) {
        id element = [myArray objectAtIndex:i];
        if(element == ...) {
            [myArray removeObjectAtIndex:i];
            i--;
        }
    }

আশাকরি এটা সাহায্য করবে...


যদিও অপ্রচলিত, আমি পরিষ্কার এবং সহজ সমাধান হতে যেতে পিছনের দিকে ঘুরতে এবং মুছতে দেখেছি। সাধারণত দ্রুততম পদ্ধতিগুলির মধ্যে একটি।
র‌্যাটারিচ

এতে দোষ কী? এটি পরিষ্কার, দ্রুত, সহজেই পঠনযোগ্য এবং এটি কবজির মতো কাজ করে। আমার কাছে এটি সেরা উত্তরের মতো দেখাচ্ছে। কেন এটি নেতিবাচক স্কোর আছে? আমি কি এখানে কিছু মিস করছি?
স্টেপ থিরিওন

1
@ স্টেফ: প্রশ্নটিতে "সূচকটি ম্যানুয়ালি আপডেট করার চেয়ে আরও দুর্দান্ত কিছু" বলে উল্লেখ করা হয়েছে।
স্টিভ ম্যাডসেন

1
উহু. আমি নিজেই-ইন্ডেক্স-সূচক-ম্যানুয়ালি অংশটি আপডেট করতে চাই না missed ধন্যবাদ স্টিভ আইএমও এই সমাধানটি বেছে নেওয়া একের চেয়ে মার্জিত (কোনও অস্থায়ী অ্যারের প্রয়োজন নেই), তাই এর বিরুদ্ধে নেতিবাচক ভোটগুলি অন্যায় বলে মনে করে।
স্টিপ থিরিওন

@ স্টিভ: আপনি যদি সম্পাদনাগুলি পরীক্ষা করে থাকেন তবে আমি আমার উত্তর জমা দেওয়ার পরে সেই অংশটি যুক্ত করা হয়েছিল .... যদি তা না হয় তবে আমি "পিছনের দিকে ইটরিটিং করাই সবচেয়ে মার্জিত সমাধান" :) দিয়ে উত্তর দিতাম। আপনার দিনটি শুভ হোক!
পোকট 0

1

আপনি অন্য NSMutableArray এ অপসারণ করার জন্য কেন বস্তুগুলি যুক্ত করবেন না। আপনি পুনরাবৃত্তি শেষ করার পরে, আপনি সংগ্রহ করেছেন এমন জিনিসগুলি সরিয়ে ফেলতে পারেন।


1

আপনি কীভাবে 'এন' উপাদান, 'এন -1' উপাদান এবং এই জাতীয় উপাদানগুলির সাথে মুছতে চান এমন উপাদানগুলি অদলবদল সম্পর্কে?

কাজ শেষ হয়ে গেলে আপনি অ্যারের আকারটি 'পূর্ববর্তী আকার - অদলবদলের সংখ্যায়' আকারে পরিবর্তন করুন


1

যদি আপনার অ্যারেতে থাকা সমস্ত অবজেক্টগুলি অনন্য হয় বা আপনি যখন পাওয়া যায় তখন কোনও বস্তুর সমস্ত উপস্থিতি সরিয়ে ফেলতে চান, আপনি খুব দ্রুত অ্যারে অনুলিপি করতে পারেন এবং মূলটি থেকে অবজেক্টটি সরাতে [NSMutableArray রিলিজঅবজেক্ট:] ব্যবহার করতে পারেন।

NSMutableArray *myArray;
NSArray *myArrayCopy = [NSArray arrayWithArray:myArray];

for (NSObject *anObject in myArrayCopy) {
    if (shouldRemove(anObject)) {
        [myArray removeObject:anObject];
    }
}

যদি মূল মাইআরিকে+arrayWithArray কার্যকর করা হয় তখন আপডেট হয় তবে কী হবে ?
বায়োফে

1
@ বাইফেফ: তারপরে আপনার কোডটিতে একটি বাগ রয়েছে। NSMutableArray থ্রেড-নিরাপদ নয়, আপনি লকগুলির মাধ্যমে অ্যাক্সেস নিয়ন্ত্রণ করবেন বলে আশা করা হচ্ছে। এই উত্তরটি
28:56

1

উপরের বেনজাদোর অ্যাঞ্জারটি হ'ল প্রিফরমেন্সের জন্য আপনার কী করা উচিত। আমার অ্যাপ্লিকেশনগুলির একটিতে অপট্রজেক্টসআইআরআরে 1 মিনিটের চলমান সময় নিয়েছে, মাত্র একটি নতুন অ্যারে যুক্ত করে .023 সেকেন্ড সময় নিয়েছে।


1

আমি এমন একটি বিভাগ নির্ধারণ করি যা আমাকে এইরকম একটি ব্লক ব্যবহার করে ফিল্টার করতে দেয়:

@implementation NSMutableArray (Filtering)

- (void)filterUsingTest:(BOOL (^)(id obj, NSUInteger idx))predicate {
    NSMutableIndexSet *indexesFailingTest = [[NSMutableIndexSet alloc] init];

    NSUInteger index = 0;
    for (id object in self) {
        if (!predicate(object, index)) {
            [indexesFailingTest addIndex:index];
        }
        ++index;
    }
    [self removeObjectsAtIndexes:indexesFailingTest];

    [indexesFailingTest release];
}

@end

যা এর পরে ব্যবহার করা যেতে পারে:

[myMutableArray filterUsingTest:^BOOL(id obj, NSUInteger idx) {
    return [self doIWantToKeepThisObject:obj atIndex:idx];
}];

1

NSMutableArray এ নীচের বিভাগ পদ্ধতিটি ব্যবহার করার জন্য একটি সুন্দর প্রয়োগ হতে পারে।

@implementation NSMutableArray(BMCommons)

- (void)removeObjectsWithPredicate:(BOOL (^)(id obj))predicate {
    if (predicate != nil) {
        NSMutableArray *newArray = [[NSMutableArray alloc] initWithCapacity:self.count];
        for (id obj in self) {
            BOOL shouldRemove = predicate(obj);
            if (!shouldRemove) {
                [newArray addObject:obj];
            }
        }
        [self setArray:newArray];
    }
}

@end

অ্যারেতে প্রতিটি অবজেক্টে প্রসেসিং করার জন্য প্রিডিকেট ব্লকটি প্রয়োগ করা যেতে পারে। যদি ভবিষ্যদ্বাণীটি সত্য হয় তবে অবজেক্টটি সরানো হবে।

অতীতে থাকা সমস্ত তারিখগুলি অপসারণের জন্য একটি তারিখ অ্যারের উদাহরণ:

NSMutableArray *dates = ...;
[dates removeObjectsWithPredicate:^BOOL(id obj) {
    NSDate *date = (NSDate *)obj;
    return [date timeIntervalSinceNow] < 0;
}];

0

পিছনে-লিয়ে ইটরেটিং করা কয়েক বছর ধরে আমার পছন্দের ছিল, তবে দীর্ঘতম সময়ের জন্য আমি কখনও এমন মামলার মুখোমুখি হইনি যেখানে 'গভীরতম' (সর্বোচ্চ গণনা) অবজেক্টটি প্রথমে সরানো হয়েছিল। মুহূর্তে পয়েন্টারটি পরবর্তী সূচকে এগিয়ে যাওয়ার আগে কিছুই নেই এবং এটি ক্র্যাশ হয়ে যায়।

বেনজাদোর উপায় এখন আমি যা করি তার নিকটতম তবে আমি কখনই বুঝতে পারি নি যে প্রতি অপসারণের পরে স্ট্যাক রদবদল হবে।

এক্সকোড 6 এর অধীনে এটি কাজ করে

NSMutableArray *itemsToKeep = [NSMutableArray arrayWithCapacity:[array count]];

    for (id object in array)
    {
        if ( [object isNotEqualTo:@"whatever"]) {
           [itemsToKeep addObject:object ];
        }
    }
    array = nil;
    array = [[NSMutableArray alloc]initWithArray:itemsToKeep];
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.