Removing elements with same value from NSMutableArray - objective-c

My NSMutableArray contains some strings as elements. One of the element is repeated many times at different indexes in the array. For example [#"", #"1,2,3",#"",#"5,3,2,1",#""].
I want to remove all the elements with value #"" from the mutable array. I tried following ways but couldn't get the solution.
Using For loop:
for(id obj in myMutableArray)
{
if([obj isEqualToString:#""])
{
[myMytableArray removeObject:obj];
}
}
Using dummy mutable array called nextMutableArray
for(id obj in myMutableArray)
{
if([obj isEqualToString:#""])
{
continue;
}
else [nextMutableArray addObject:obj];
}
In both the ways, elements (#"") at other indexes are removed but not at the index 0 (first object). What could be the possible reason? Is there any way to remove all the elements that contain string #"" from the mutable array?

one option is to filter your array using predicates:
NSArray *someArray = #[#"", #"1,2,3", #"", #"5,3,2,1", #""];
NSLog(#"%#", someArray);
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF != ''"];
NSArray *filteredArray = [someArray filteredArrayUsingPredicate:predicate];
NSLog(#"%#", filteredArray);

No Need of For loop. Simply use this.
[mutableArray removeObjectIdenticalTo:#""];

If you want to remove duplicate entries from an array, You can use NSSet Class.
NSSet did not accept duplicate/s value.
NSMutableArray *arrTest=[[NSMutableArray alloc]initWithObjects:#"", #"1,2,3",#"",#"5,3,2,1",#"", nil];
NSSet *set = [NSSet setWithArray:arrTest];
arrTest = [[set allObjects] mutableCopy];
or
You can do like this:
NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(id str, NSDictionary *unused) { return ![str isEqualToString:#""]; }];
arrTest = [[arrTest filteredArrayUsingPredicate:predicate]mutableCopy];
This is fast and simple way.

Related

filter dictionary array by property that matches a different array

I have two arrays and I'm trying to filter the first (array1) with a matching property that exists in a second array (array2). The first array is a dictionary array with key 'name'. The second array is an array of objects with property 'name'. Is it possible to filter contents of 'array1' and display only those that have a matching 'name' found in 'array2'?
I've tried:
NSPredicate *pred = [NSPredicate predicateWithFormat:#"name == #%",self.array2];
NSArray *results = [array1 filteredArrayUsingPredicate:pred];
NSLog(#"The results array is %#", results);
Rather than '==' I've tried a mix of 'IN' and '#K' and 'self' but it either crashes or results are 0.
NSPredicate *pred = [NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) {
return [[array2 valueForKey:#"name"] containsObject:[evaluatedObject objectForKey:#"name"]];
}];
This should work with IN:
NSArray *matchSet = [self.array2 valueForKey:#"name"];
NSPredicate *pred = [NSPredicate predicateWithFormat:#"name IN #%",matchSet];
Typed in Safari.
https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/Predicates/Articles/pSyntax.html#//apple_ref/doc/uid/TP40001795-215891
Here's a quick example of how you could accomplish this:
int main(int argc, const char * argv[])
{
#autoreleasepool {
NSArray *arrayOne = #[#{#"name": #"Alvin"}, #{#"name": #"Brian"}, #{#"name": #"Charlie"}];
BMPPerson *alvin = [[BMPPerson alloc] initWithName:#"Alvin"];
BMPPerson *charlie = [[BMPPerson alloc] initWithName:#"Charlie"];
NSArray *arrayTwo = #[alvin, charlie];
NSArray *values = [arrayTwo valueForKey:#"name"];
NSMutableArray *filteredValues = [NSMutableArray array];
[arrayOne enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSString *name = [obj valueForKey:#"name"];
if ([values containsObject:name]) {
[filteredValues addObject:name];
}
}];
NSLog(#"%#", filteredValues);
}
return 0;
}
In the example, arrayOne is an NSArray of NSDictionary objects. Each object has a key of name.
The objects contained in arrayTwo are a basic NSObject subclass that has a name property.
To get the values of the name properties for all of the objects in arrayTwo we make use of the key-value coding method -valueForKey: which calls -valueForKey: on each object in the receiver and returns an array of the results.
We then create an NSMutableArray to hold the filtered results from arrayOne.
Next we enumerate the objects in arrayOne using the -enumerateObjectsUsingBlock: method. In this example, we know that the obj argument is an NSDictionary that has a key of name. Instead of casting to an NSDictionary and calling -objectForKey: we can simply call -valueForKey: and store the value in our local variable name. We then check to see if name is in the values array and if it is, add it to our filteredValues.

NSPredicate, search in a NSArray, inside a NSArray of NSDict

I have a NSArray of NSDictionary.
One of the keys of the NSDictionary contains a NSArray of strings.
Is there a way that I can use NSPredicate to find a specific strins in that Array of strings?
Thanks :)
Also: This work great, but not for sublevelArray
predicate = [NSPredicate predicateWithFormat:#" %K LIKE[cd] %#", sKey, sLookForString];
Just replace LIKE with CONTAINS in your format string. For example, given this array:
NSArray *dogs = #[#{#"name" : #"Fido",
#"toys" : #[#"Ball", #"Kong"]},
#{#"name" : #"Rover",
#"toys" : #[#"Ball", #"Rope"]},
#{#"name" : #"Spot",
#"toys" : #[#"Rope", #"Kong"]}];
...the following predicate can be used obtain a filtered array containing only the dictionaries where the value for the key toy is an array that contains the string Kong.
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"%K CONTAINS[cd] %#", #"toys", #"Kong"];
On NSArray you can use filteredArrayUsingPredicate:, on NSDictionary use enumerateKeysAndObjectsUsingBlock: and then for each value do either a filteredArrayUsingPredicate: if it is an NSArray or you can use evaluateWithObject: using the predicate itself.
If you want to filter the array of dictionaries based on the array of strings, you can use -predicateWithBlock to filter the array, as shown in the code below:
- (NSArray *)filterArray:(NSArray *)array WithSearchString:(NSString *)searchString {
NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) {
NSDictionary *dictionary = (NSDictionary *)evaluatedObject;
NSArray *strings = [dictionary objectForKey:#"strings"];
return [strings containsObject:searchString];
}];
return [array filteredArrayUsingPredicate:predicate];
}

Searching NSArray using suffixes

I have a word list stored in an NSArray, I want to find all the words in it with the ending 'ing'.
Could someone please provide me with some sample/pseudo code.
Use NSPredicate to filter NSArrays.
NSArray *array = #[#"test", #"testing", #"check", #"checking"];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF ENDSWITH 'ing'"];
NSArray *filteredArray = [array filteredArrayUsingPredicate:predicate];
Let's say you have an array defined:
NSArray *wordList = // you have the contents defined properly
Then you can enumerate the array using a block
// This array will hold the results.
NSMutableArray *resultArray = [NSMutableArray new];
// Enumerate the wordlist with a block
[wordlist enumerateObjectsUsingBlock:(id obj, NSUInteger idx, BOOL *stop) {
if ([obj hasSuffix:#"ing"]) {
// Add the word to the result list
[result addObject:obj];
}
}];
// resultArray now has the words ending in "ing"
(I am using ARC in this code block)
I am giving an example using blocks because its gives you more options should you need them, and it's a more modern approach to enumerating collections. You could also do this with a concurrent enumeration and get some performance benefits as well.
Just loop through it and check the suffixes like that:
for (NSString *myString in myArray) {
if ([myString hasSuffix:#"ing"]){
// do something with myString which ends with "ing"
}
}
NSMutableArray *results = [[NSMutableArray alloc] init];
// assuming your array of words is called array:
for (int i = 0; i < [array count]; i++)
{
NSString *word = [array objectAtIndex: i];
if ([word hasSuffix: #"ing"])
[results addObject: word];
}
// do some processing
[results release]; // if you're not using ARC yet.
Typed from scratch, should work :)

Searching on the properties of objects in an array

I have an NSArray of objects with properties such as firstName, lastName, clientID etc. and i would like to perform a search on the array based on a search keyword. This keyword must be checked against the first name and the last name properties and return a subset of the original array that contains only those objects whose first/last name contain the search term. Is there any efficient/fast way to do this?
As a second thought, I think -filteredArrayUsingPredicate: might be better for you.
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"%K = %#", #"firstName", #"Bob"];
NSArray *filteredArray = [array filteredArrayUsingPredicate:predicate];
This returns a sub-array of objects from the array that have the first name of "Bob".
I think your looking for -indexesOfObjectsPassingTest:
NSIndexSet *indexSet = [array indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
MyObject *myObject = (MyObject *)obj;
return [myObject.firstName isEqualToString:#"Bob"];
}];
This returns an index set of all the objects in the array with the first name of "Bob".
Another approach returning a new array containing only matching objects:
-(NSArray *)matchingClientsFromArray:(NSArray *)objects withFirstName:(NSString *)firstName andLastName:(NSString *)lastName{
NSMutableArray *objectArray = [NSMutableArray new];
for (Client *client in objectArray){
if ([client.firstName isEqualToString:firstName] &&
[client.lastName isEqualToString:lastName]) {
[objectArray addObject:client];
}
}
return [objectArray copy];
}

Better solution for this 2x fast-enumeration?

I'm looping through an array and comparing the objects tag property in this array with the objects in another array.
Here's my code:
NSArray *objectsArray = ...;
NSArray *anotherObjectArray = ...;
NSMutableArray *mutableArray = ...;
for (ObjectA *objectA in objectsArray) {
for (ObjectZ *objectZ in anotherObjectArray) {
if ([objectA.tag isEqualToString:objectZ.tag]) {
[mutableArray addObject:objectA];
}
}
}
Is there a better way to do this?
Please note the tag property is not an integer, so have to compare strings.
You can do this by iterating over each array once, rather than nesting:
NSMutableSet *tagSet = [NSMutableSet setWithCapacity:[anotherObjectArray count]];
for(ObjectZ *objectZ in antherObjectArray) {
[tagSet addObject:objectZ.tag];
}
NSMutableArray *output = [NSMutableArray mutableArray];
for(ObjectA *objectA in objectsArray) {
if([tagSet containsObject:objectA.tag]) {
[output addObject:objectA];
}
}
May be you can use [NSArray filteredArrayUsingPredicate:]; - http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSArray_Class/NSArray.html
But you may have to tweak for property tag yourself.
NSArray *objectsArray = [NSArray arrayWithObjects:#"Miguel", #"Ben", #"Adam", #"Melissa", nil];
NSArray *tagsArray = [NSArray arrayWithObjects:#"Miguel", #"Adam", nil];
NSPredicate *sPredicate = [NSPredicate predicateWithFormat:#"SELF IN %#", tagsArray];
NSArray *results = [objectsArray filteredArrayUsingPredicate:sPredicate];
NSLog(#"Matched %d", [results count]);
for (id a in results) {
NSLog(#"Object is %#", a);
}
Hope this helps
Well, the simplest change (as there can only be one match per objectA) then you could do a break after your [mutableArray addObject:objectA]. When a match occurs, that would reduce the inner loop by 50%.
More dramatically, if you're doing this a lot and the order of anotherObjectArray doesn't matter, would be to invert your anotherObjectArray data structure and use a dictionary, storing the objects by tag. Then you just iterate over objectA asking if its tag is in the dictionary of ObjectZs.
Thanks for all the answers. While I have accepted the NSMutableSet solution, I actually ended up going with the following, as it turned out it was a tiny bit faster:
NSMutableDictionary *tagDictionary = [NSMutableDictionary dictionaryWithCapacity:[anotherObjectArray count]];
for (ObjectZ *objectZ in anotherObjectArray) {
[tagDictionary setObject:objectZ.tag forKey:objectZ.tag];
}
for (ObjectA *objectA in objectsArray) {
if ([tagDictionary objectForKey:objectA.tag]) {
[direction addObject:objectA];
}
}