check and remove a particular string from nsmutable array without index - objective-c

In Xcode, I store some NSString in NSMutableArray.
Hello
Here
MyBook
Bible
Array
Name2
There
IamCriminal
User can enter string.
Name2
I need to delete that particular string from NSMutableArray without knowing index of the string. I have some idea that, Use iteration. Any other Best way. Plz Give with sample codings.

you can use containsObject method in an NSMutableArray
if ([yourArray containsObject:#"object"]) {
[yourArray removeObject:#"object"];
}
Swift:
if yourArray.contains("object") {
yourArray = yourArray.filter{ $0 != "object" }
}

[array removeObject:#"Name2"];
The documentation for NSMutableArray’s removeObject: method states:
matches are determined on the basis of an object’s response to the
isEqual: message
In other words, this method iterates over your array comparing the objects to #"Name2". If an object is equal to #"Name2", it is removed from the array.

[array removeObject:#"name2"];

You can try this
for(NSString *string in array)
{
if([[string lowercasestring] isEqualToSring:[yourString lowercasestring]])
{
[array removeObject:string];
break;
}
}

YOu can simply use
[yourArray removeObject:stringObjectToDelete];
This method uses indexOfObject: to locate matches and then removes them by using removeObjectAtIndex:. Thus, matches are determined on the basis of an object’s response to the isEqual: message. If the array does not contain anObject, the method has no effect.

Try this,
BOOL flag = [arrayName containsObject:Str];
if (flag == YES)
{
[arrayName removeObject:Str];
}

Related

How to find if an object of a class with same data already exists in a NSMutableArray?

I apologize for this basic question, but I am 2-month new to obj-c.
Problem:
I am not able to find if an object with same data already exists in the NSMutableArray.
What I am doing?
ScanDigInfoForTable* sfile = [[ScanDigInfoForTable alloc]init];
sfile.data = "myData";
int inde = [_DataList indexOfObject:sfile] ;
if(inde == -1)
[_DataList addObject:sfile];
ScanDigInfoForTable* sfile2 = [[ScanDigInfoForTable alloc]init];
sfile2.data = "myData";
inde = [_DataList indexOfObject:sfile2] ;
if(inde == -1)
[_DataList addObject:sfile2];
Issue:
The _DataList get 2 objects instead of 1. Many thanks in advance for your attention.
S.P: I already know that I may traverse the whole array in a loop in order to check the data already exists. Looking for a better solution as the array may have thousands of records.
Well, comparing two custom objects is really not that simple for the simple fact there is no defined way to declare equality. It is individual choice to define the rules for equality for the objects they are creating.
In your case, it would be two step process:
Step 1: Implement isEqual: in your ScanDigInfoForTable class. Assuming ScanDigInfoForTable is a model class and that it has three string properties - code, data & itemID (you can have any type).
- (BOOL)isEqual:(ScanDigInfoForTable *)other {
return [self.code isEqualToString:other.code] && [self.data isEqualToString:other.data] && [self.itemID isEqualToString:other.itemID];
}
Step 2: Call containsObject: method on NSMutableArray. This method would internally call isEqual: to give you the results based on the rules you defined.
// If the object does not exist in the list, we add it
if (![_DataList containsObject:sfile2]) {
[_DataList addObject:sfile2];
}
In Objective-C object equality is determined by the methods -isEqual: and -hash.
When testing object membership in a collection the items of the collection are sent isEqual:. The default implementation only compares the addresses of objects, which is why you are seeing duplicates. Your objects do no provide their own implementation of equality based on the data they contain.
To fix this you can override isEqual: to compare objects based on the data they represent. Using your example in your question, this could just be:
- (BOOL) isEqual:(id)object {
BOOL result = N0;
if (object != self){
if ([object isKindOfClass:[self class]]){
result = [[self data] isEqual:[(ScanDigInfoForTable *)object data]];
}
} else {
result = YES;
}
return result;
}
Mike Ash has a great article about implementing equality. In general, if you are implementing a custom class you should make equality a part of that.
You can user filteredArrayUsingPredicate for example
NSArray * matches = [_DataList filteredArrayUsingPredicate:
[NSPredicate predicateWithFormat:#"data == %# ",sfile2.data]];
if(matches.count == 0) {
[_DataList addObject:sfile2];
}
Something like this?
NSMutableSet* set1 = [NSMutableSet setWithArray:array1];
NSMutableSet* set2 = [NSMutableSet setWithArray:array2];
[set1 intersectSet:set2]; //this will give you only the obejcts that are in both sets
NSArray* result = [set1 allObjects];
This has the benefit of not looking up the objects in the array, while looping through another array, which has N^2 complexity.
and also set2 doesn't have to be mutable, might as well use just
NSSet* set2 = [NSSet setWithArray:array2];

How to recognize the first element in Objective-C style enumeration?

I have an NSMutableArray of NSNumbers, I want to enumerate through all of them with Objective-C styled enumeration. Here's what I've done so far.
for ( NSNumber* number in array )
{
//some code
}
I want to be able to recognize the first object fast, I am able to do this of course,
if ( [array indexOfObject:number] == 0 )
{
//if it's the first object
}
Is there any way to do this faster? There's of course the old-fashioned C style way, and remove the object from array first, and then put it back after enumeration. Just want to know if there's a better technic.
You can try using a method that provides the index of the object currently being enumerated:
[array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if (idx == 0) {
// this is the first object
}
}];
Or if you simply want to access the first object of an array:
id obj = [array objectAtIndex:0];
or with the new Objective-C style/syntax:
id obj = array[0];
This solution is faster than accessing and comparing the first array element:
BOOL firstIteration = YES;
for (NSNumber *number in array) {
if (firstIteration) {
// Handle first iteration
firstIteration = NO;
}
// Do something
}
In fast enumeration you cant alter the array. So if you want to remove you have to use old style for(;;) loop.
To find the first object simply use [array objectAtIndex:0]

Finding the index of an object in an array using one of that object's properties

I have a NSMutableArray pages with several objects (instances of Page). Each Page instance has a UUID and other properties, such as contents. When a page changes, everything may change except the UUID. After a change, I would like to find out the index of a particular Page in pages by using indexOfObject:. I use the UUID to identify the index I'm looking for and this works just fine:
NSMutableArray *uuids = [[NSMutableArray alloc] init];
for (int i = 0; i < [self.pages count]; i++) {
[uuids addObject:[[pages objectAtIndex:i] uuid]];
}
NSUInteger indexOfPage = [uuids indexOfObject:page.uuid];
Now my question is if there is a more elegant way to do this. All I really need is the index of the Page object in pages that has a given UUID.
There is
- (NSIndexSet *)indexesOfObjectsPassingTest:(BOOL (^)(id obj, NSUInteger idx, BOOL *stop))predicate or indexOfAccessibilityElement:<#(id)#> but I'm not really sure how either of these could help me out with my problem.
Subclass the isEqual: method in Page as follows:
- (BOOL) isEqual: (Page *) otherPage
{
if (![otherPage isKindOfClass:[Page class]]) {
return NO;
}
return [self.UUID isEqualToString: otherPage.UUID];
}
Then indexOfObject: will work correctly.
From Apple's NSArray documentation:
Starting at index 0, each element of the array is sent an isEqual:
message until a match is found or the end of the array is reached.
This method passes the anObject parameter to each isEqual: message.
Objects are considered equal if isEqual: (declared in the NSObject
protocol) returns YES.
From NSArray docs:
each element of the array is sent an isEqual: message until a match is found or the end of the array is reached.
So you can override isEqual: so that it returns YES if the two pages has the same UUID.
- (BOOL)isEqual:(id)object {
if (![object isKindOfClass:[Page class]]) {
return NO;
}
Page *otherPage = object;
return [self.uuid isEqualToString:otherPage.uuid];
}
May be this way by using a predicate, assuming pages is your array of all pages:
predicate = [NSPredicate predicateWithFormat:[NSString stringWithFormat:#"(UUID == %#)", searchUUID]];
filteredArray = [pages filteredArrayUsingPredicate:predicate];
And once you have the object, which should be at objectAtIndex:0 in the filtered array assuming your uuid is unique, you could ask the index of that object:
NSUInteger indexOfPage = [pages indexOfObject:theObject];

How to perform binary search on NSArray?

What is the simplest way to do a binary search on an (already) sorted NSArray?
Some potential ways I have spotted so far include:
The use of CFArrayBSearchValues (mentioned here) - would this work on an NSArray?
The method indexOfObject:inSortedRange:options:usingComparator: of NSArray assumes the array is sorted and takes an opts param of type NSBinarySearchingOptions - does this mean it performs a binary search? The docs just say:
Returns the index, within a specified range, of an object compared with elements in the array using a given NSComparator block.
Write my own binary search method (something along the lines of this).
I should add that I am programming for iOS 4.3+
Thanks in advance.
The second option is definitely the simplest. Ole Begemann has a blog entry on how to use the NSArray's indexOfObject:inSortedRange:options:usingComparator: method:
NSArray *sortedArray = ... // must be sorted
id searchObject = ...
NSRange searchRange = NSMakeRange(0, [sortedArray count]);
NSUInteger findIndex = [sortedArray indexOfObject:searchObject
inSortedRange:searchRange
options:NSBinarySearchingFirstEqual
usingComparator:^(id obj1, id obj2)
{
return [obj1 compare:obj2];
}];
See NSArray Binary Search
1 and 2 will both work. #2 is probably easier; it certainly doesn't make sense for that method to do anything other than a binary search (if the range is above a certain size, say). You could verify on a large array that it only does a small number of comparisons.
I'm surprised that nobody mentioned the use of NSSet, which [when it contains objects with a decent hash, such as most Foundation data types] performs constant time lookups. Instead of adding your objects to an array, add then to a set instead (or add them to both if you need to retain a sorted order for other purposes [or alternatively on iOS 5.0 or Mac OS X 10.7 there is NSOrderedSet]).
To determine whether an object exists in a set:
NSSet *mySet = [NSSet setWithArray:myArray]; // try to do this step only once
if ([mySet containsObject:someObject])
{
// do something
}
Alternatively:
NSSet *mySet = [NSSet setWithArray:myArray]; // try and do this step only once
id obj = [mySet member:someObject];
// obj is now set to nil if the object doesn't exist or it is
// set to an object that "isEqual:" to someObject (which could be
// someObject itself).
It is important to know that you will lose any performance benefit if you convert the array to a set each time you do a lookup, ideally you will be using a preconstructed set containing the objects you want to test.
//Method to pass array and number we are searching for.
- (void)binarySearch:(NSArray *)array numberToEnter:(NSNumber *)key{
NSUInteger minIndex = 0;
NSUInteger maxIndex = array.count-1;
NSUInteger midIndex = array.count/2;
NSNumber *minIndexValue = array[minIndex];
NSNumber *midIndexValue = array[midIndex];
NSNumber *maxIndexValue = array[maxIndex];
//Check to make sure array is within bounds
if (key > maxIndexValue || key < minIndexValue) {
NSLog(#"Key is not within Range");
return;
}
NSLog(#"Mid indexValue is %#", midIndexValue);
//If key is less than the middleIndexValue then sliceUpArray and recursively call method again
if (key < midIndexValue){
NSArray *slicedArray = [array subarrayWithRange:NSMakeRange(minIndex, array.count/2)];
NSLog(#"Sliced array is %#", slicedArray);
[self binarySearch:slicedArray numberToEnter:key];
//If key is greater than the middleIndexValue then sliceUpArray and recursively call method again
} else if (key > midIndexValue) {
NSArray *slicedArray = [array subarrayWithRange:NSMakeRange(midIndex+1, array.count/2)];
NSLog(#"Sliced array is %#", slicedArray);
[self binarySearch:slicedArray numberToEnter:key];
} else {
//Else number was found
NSLog(#"Number found");
}
}
//Call Method
#interface ViewController ()
#property(nonatomic)NSArray *searchArray;
#end
- (void)viewDidLoad {
[super viewDidLoad];
//Initialize the array with 10 values
self.searchArray = #[#1,#2,#3,#4,#5,#6,#7,#8,#9,#10];
//Call Method and search for any number
[self binarySearch:self.searchArray numberToEnter:#5];
// Do any additional setup after loading the view, typically from a nib.
}
CFArrayBSearchValues should work—NSArray * is toll-free bridged with CFArrayRef.

How do Arrays behave in Objective-C?

I've always had my doubts about Arrays.
If an Array's count is 7, and I replace the SECOND elements with 'NULL', does it still have count 7?
If an Array's count is 7, and I replace the LAST elements with 'NULL', does it still have count 7? Or will it have count 6?
I need to know this behavior to make a function that removes the first element of the Array (place '0'), and the other elements of the Array swap one place to the front.
- (void) eat {
[foodArray replaceObjectAtIndex:0 withObject:NULL];
for (int i = 0; i<[foodArray count]-1; ++i){
[foodArray replaceObjectAtIndex:i withObject:[foodArray objectAtIndex:i+1]];
}
[foodArray replaceObjectAtIndex:[foodArray count]-1 withObject:NULL];
}
Would that work?
(Thanks!)
Edit: I've just noticed the first line isn't necessary, as I'm already replacing the first element later. Am I wrong?
If you want to remove an object from an array, just use [foodArray removeObjectAtIndex:]. The way you're doing it you're just leaving a null value in the array.
Just remove the item:
- (void) eat {
[foodArray removeObjectAtIndex:0];
}
Inorder to add/remove array elements the array must be mutable: NSMutableArray so foodArray must be a NSMutableArray.
Trying to keep NULL in an array is bad idea in general.
If you need to use some kind of placeholder - it's better to use an instance of NSNull class.
Later you can check type of the object using class name check:
if( [objectFromArray isKindOfClass:[NSNull class]] == YES )
{ // This is NSNull instance, not real object }