Search through data Multidimensional array - objective-c

i've have this NSMutableArray called finalArray where i add the name and a image.
[finalArray addObject:#[name, image]];
in the following method its searching through the finalarray, but because its not expecting a multidimensional array it seem to give an error. How can i in this code:
self.filteredArray = [[finalArray filteredArrayUsingPredicate:predicate] mutableCopy];
get all the name objects from the finalArray? since that is what this code expect:
[[finalArray filteredArrayUsingPredicate:predicate]
the method:
-(void) searchThroughdata {
self.filteredArray = nil;
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF contains [c] %#",self.searchBar.text];
self.filteredArray = [[finalArray filteredArrayUsingPredicate:predicate] mutableCopy];
[tableViewData reloadData];
}
How do i add the image that belong to the name in the finalarray and still only search through the names like it do now with this?
[[finalArray filteredArrayUsingPredicate:predicate] mutableCopy];

It looks like you are trying to associate names and images with each other by using the same index of an array or something? Am I right?
If so then you should really be using a custom class to do this...
#interface MyNameImageClass : NSObject
#property NSString *name;
#property UIImage *image;
#end
Now you can create the object...
MyNameImageClass *object = [MyNameImageClass new];
object.name = theName;
object.image = theImage;
Then just add this to an array...
[finalArray addObject:object];
Having said that though, you need to clarify what you are asking. The question is very confusing.
By doing this if the image is updated on the object you don't need to reinsert it into the array. The array stores a reference to the object so the array will have the updated value too.

Related

How to add new array element from another method in Objective-c?

I have some array( #private NSArray employees []; ) and method , which take string parameter( name of employees) and put this parameter in array. How I can do this with Objective-c?
You could do the following,
Create a property,
#property (nonatomic) NSMutableArray *array;
Initialise the array in your init method or somewhere else appropriate,
self.array = [[NSMutableArray alloc] init];
Your method could look something like this,
- (void)addEmployeeName:(NSString *)employeeName {
[self.array addObject:employeeName];
}
You can create a class Employee and use a type with your array.
For example:
NSArray<Employee*> * employees = [[NSArray alloc] init];
At this point, your method will be:
-(Employee *)createEmployee:(NSString *)name{
Employee *myEmpl = [[Employee alloc]init];
[myEmpl setName:name];
return myEmpl;
}
and you can add the object (of type Employee) in your array in this way:
[employees addObject:[self createEmployee]];
the same thing is possibile with an object of type NSString instead of Employee.
You can also avoid defining the type in your NSArray because Objective-C use the type inference

Add a tag to NSMutableArray

Is it possible to set a tag for an NSMutableArray? I have to somehow determine, in an array of arrays, the single array which needs to be rewritten, and if I could just set the tag to that inner array to 1 (or some other number), this would be extremely easy.
Example:
NSMutableArray* outerArray = [NSMutableArray new];
NSMutableArray* innerArray1 = [NSMutableArray new];
NSMutableArray* innerArray2 = [NSMutableArray new];
NSMutableArray* innerArray3 = [NSMutableArray new];
NSMutableArray* innerArray4 = [NSMutableArray new];
[outerArray addObject:innerArray1];
[outerArray addObject:innerArray2];
[outerArray addObject:innerArray3];
[outerArray addObject:innerArray4];
//now let's say innerArray1 needs to be rewritten
//I would like to be able to do this
[innerArray1 setTag:100];
//then later, when I need to determine which of the arrays inside outerArray
//needs to be rewritten, I can just do this
for(NSMutableArray* temp in outerArray) {
if(temp.tag == 100) {
//do what I need to do
}
}
But you can't use setTag: with NSMutableArrays. What would be a workaround?
Arrays are ordered collections, so why don't you just keep track of which index needs to be rewritten.
When something happens such that the array at index 0 (which, in your example, would be innerArray1) of outer array needs to be written, cache index 0 -- as a property if this routine needs to span across separate methods.
Then, when it comes time to do the rewrite, consult the cached index. Retrieve the array to be rewritten like this: NSArray *arrayToRewrite = [outerArray objectAtIndex:cachedIndexToRewrite]; Or access it directly: [[outerArray objectAtIndex:cachedIndexToRewrite] replaceObjectAtIndex:whatever withObject:whatever];
You could use an NSMutableDictionary instead. The "tag" would just be the key and the array would be the value.
Use associated objects. You can even add a category to NSMutableArray that would add a tag property to them.
#interface NSMutableArray (TagExtension)
#property (nonatomic, assign) NSInteger tag;
#end
#implementation NSMutableArray (TagExtension)
#dynamic tag;
static char TagExtensionKey;
-(NSInteger)tag {
NSNumber *ourTag = (NSNumber *)objc_getAssociatedObject(self, &TagExtensionKey);
if( ourTag ) {
return( [ourTag integerValue] );
}
return(0);
}
-(void)setTag:(NSInteger)newTag {
objc_setAssociatedObject(self, &TagExtensionKey, [NSNumber numberWithInteger:newTag], OBJC_ASSOCIATION_RETAIN);
}
#end
See also: How to add properties to NSMutableArray via category extension?
Not sure why a dictionary is a bad idea here… as alternatives, you can:
remember the index
or if each entry is a unique array, you can simply refer to it by pointer:
NSArray * tagged = theArray;
for (NSMutableArray * at in outerArray) {
if (tagged == at) {
//do what I need to do
}
}
Make your inner arrays class variables. Then you can just access them as:
for(NSMutableArray* temp in outerArray) {
if(temp == self.innerArray1) {
//do what I need to do
}

How do you enumerate through an array in Obj-C?

I have an array which has several objects (all of different classes) in it. But using enumeration doesn't work on it for some reason.
NSString *arrayString;
NSURL *arrayUrl;
NSProcessInfo *arrayPr;
NSDictionary *arrayDictionary;
NSMutableString *arrayMString;
NSMutableArray *objectArray = [NSMutableArray arrayWithObjects:arrayString,arrayUrl,arrayPr,arrayDictionary,arrayMString,nil];
for( NSString *item in objectArray ){
NSLog(#"Class name is: %#", [item className]);
}
I think it might be something to do with how the objects are been added to the array but i'm new to objective-c and not sure.
you aren't actually populating the array.
NSString *arrayString;
declares a variable, arrayString, of type NSString. it's not initialized (so it deserves to crash when you use the variable -- but may be 0 with some build settings).
so, to assign a variable:
NSString *arrayString = [NSString stringWithFormat:#"sksjdhf %f\n", 3.3];
arrayWithObjects adds objects from the (va list) argument until nil/null/0 is encountered.
you must set up the remainder of your variables/arguments correctly before using them.
this should work as you expect it to:
NSString * str = #"a string";
NSMutableArray *objectArray = [NSMutableArray arrayWithObjects:str, nil];
for (NSObject * item in objectArray) {
NSLog(#"Class name is: %#", [item className]);
}
In the for loop, use an id data type. The id data type is a general purpose data type that can be used to store a reference to any object.
For example:
for ( id item in objectArray ) {
NSLog(#"Class name is: %#", [item className]);
}
Yep, that's how you do it. If you're having trouble, it is not in the enumeration syntax itself.

Removing duplicates from array based on a property in Objective-C

I have an array with custom objects. Each array item has a field named "name". Now I want to remove duplicate entries based on this name value.
How should I go about achieving this?
I do not know of any standard way to to do this provided by the frameworks. So you will have to do it in code. Something like this should be doable:
NSArray* originalArray = ... // However you fetch it
NSMutableSet* existingNames = [NSMutableSet set];
NSMutableArray* filteredArray = [NSMutableArray array];
for (id object in originalArray) {
if (![existingNames containsObject:[object name]]) {
[existingNames addObject:[object name]];
[filteredArray addObject:object];
}
}
You might have to actually write this filtering method yourself:
#interface NSArray (CustomFiltering)
#end
#implementation NSArray (CustomFiltering)
- (NSArray *) filterObjectsByKey:(NSString *) key {
NSMutableSet *tempValues = [[NSMutableSet alloc] init];
NSMutableArray *ret = [NSMutableArray array];
for(id obj in self) {
if(! [tempValues containsObject:[obj valueForKey:key]]) {
[tempValues addObject:[obj valueForKey:key]];
[ret addObject:obj];
}
}
[tempValues release];
return ret;
}
#end
I know this is an old question but here is another possibility, depending on what you need.
Apple does provide a way to do this -- Key-Value Coding Collection Operators.
Object operators let you act on a collection. In this case, you want:
#distinctUnionOfObjects
The #distinctUnionOfObjects operator returns an array containing the distinct objects in the property specified by the key path to the right of the operator.
NSArray *distinctArray = [arrayWithDuplicates valueForKeyPath:#"#distinctUnionOfObjects.name"];
In your case, though, you want the whole object. So what you'd have to do is two-fold:
1) Use #distinctUnionOfArrays instead. E.g. If you had these custom objects coming from other collections, use #distinctUnionOfArray.myCollectionOfObjects
2) Implement isEqual: on those objects to return if their .name's are equal
I'm going to get flak for this...
You can convert your array into a dictionary. Not sure how efficient this is, depends on the implementation and comparison call, but it does use a hash map.
//Get unique entries
NSArray *myArray = #[#"Hello", #"World", #"Hello"];
NSDictionary *uniq = [NSDictionary dictionaryWithObjects:myArray forKeys:myArray];
NSLog(#"%#", uniq.allKeys);
*Note, this may change the order of your array.
If you'd like your custom NSObject subclasses to be considered equal when their names are equal you may implement isEqual: and hash. This will allow you to add of the objects to an NSSet/NSMutableSet (a set of distinct objects).
You may then easily create a sorted NSArray by using NSSet's sortedArrayUsingDescriptors:method.
MikeAsh wrote a pretty solid piece about implementing custom equality: Friday Q&A 2010-06-18: Implementing Equality and Hashing
If you are worried about the order
NSArray * newArray =
[[NSOrderedSet orderedSetWithArray:oldArray] array]; **// iOS 5.0 and later**
It is quite simple in one line
NSArray *duplicateList = ...
If you don't care about elements order then (unordered)
NSArray *withoutDUP1 = [[NSSet setWithArray:duplicateList] allObjects];
Keep the elements in order then (ordered)
NSArray *withoutDUP2 = [[NSOrderedSet orderedSetWithArray:duplicateList] array];
Implement isEqual to make your objects comparable:
#interface SomeObject (Equality)
#end
#implementation SomeObject (Equality)
- (BOOL)isEqual:(SomeObject*)other
{
return self.hash == other.hash;
}
- (NSUInteger)hash
{
return self.name;///your case
}
#end
How to use:
- (NSArray*)distinctObjectsFromArray:(NSArray*)array
{
return [array valueForKeyPath:#"#distinctUnionOfObjects.self"];
}

filtering NSArray into a new NSArray in Objective-C

I have an NSArray and I'd like to create a new NSArray with objects from the original array that meet certain criteria. The criteria is decided by a function that returns a BOOL.
I can create an NSMutableArray, iterate through the source array and copy over the objects that the filter function accepts and then create an immutable version of it.
Is there a better way?
NSArray and NSMutableArray provide methods to filter array contents. NSArray provides filteredArrayUsingPredicate: which returns a new array containing objects in the receiver that match the specified predicate. NSMutableArray adds filterUsingPredicate: which evaluates the receiver’s content against the specified predicate and leaves only objects that match. These methods are illustrated in the following example.
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" }
There are loads of ways to do this, but by far the neatest is surely using [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.
}]];
I think that's about as concise as it gets.
Swift:
For those working with NSArrays in Swift, you may prefer this even more concise version:
let filteredArray = array.filter { $0.shouldIKeepYou() }
filter is just a method on Array (NSArray is implicitly bridged to Swift’s Array). It takes one argument: a closure that takes one object in the array and returns a Bool. In your closure, just return true for any objects you want in the filtered array.
Based on an answer by Clay Bridges, here is an example of filtering using blocks (change yourArray to your array variable name and testFunc to the name of your testing function):
yourArray = [yourArray objectsAtIndexes:[yourArray indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
return [self testFunc:obj];
}]];
If you are OS X 10.6/iOS 4.0 or later, you're probably better off with blocks than NSPredicate. See -[NSArray indexesOfObjectsPassingTest:] or write your own category to add a handy -select: or -filter: method (example).
Want somebody else to write that category, test it, etc.? Check out BlocksKit (array docs). And there are many more examples to be found by, say, searching for e.g. "nsarray block category select".
Assuming that your objects are all of a similar type you could add a method as a category of their base class that calls the function you're using for your criteria. Then create an NSPredicate object that refers to that method.
In some category define your method that uses your function
#implementation BaseClass (SomeCategory)
- (BOOL)myMethod {
return someComparisonFunction(self, whatever);
}
#end
Then wherever you'll be filtering:
- (NSArray *)myFilteredObjects {
NSPredicate *pred = [NSPredicate predicateWithFormat:#"myMethod = TRUE"];
return [myArray filteredArrayUsingPredicate:pred];
}
Of course, if your function only compares against properties reachable from within your class it may just be easier to convert the function's conditions to a predicate string.
NSPredicate is nextstep's way of constructing condition to filter a collection (NSArray, NSSet, NSDictionary).
For example consider two arrays arr and filteredarr:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF contains[c] %#",#"c"];
filteredarr = [NSMutableArray arrayWithArray:[arr filteredArrayUsingPredicate:predicate]];
the filteredarr will surely have the items that contains the character c alone.
to make it easy to remember those who little sql background it is
*--select * from tbl where column1 like '%a%'--*
1)select * from tbl --> collection
2)column1 like '%a%' --> NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF contains[c] %#",#"c"];
3)select * from tbl where column1 like '%a%' -->
[NSMutableArray arrayWithArray:[arr filteredArrayUsingPredicate:predicate]];
I hope this helps
Checkout this library
https://github.com/BadChoice/Collection
It comes with lots of easy array functions to never write a loop again
So you can just do:
NSArray* youngHeroes = [self.heroes filter:^BOOL(Hero *object) {
return object.age.intValue < 20;
}];
or
NSArray* oldHeroes = [self.heroes reject:^BOOL(Hero *object) {
return object.age.intValue < 20;
}];
The Best and easy Way is to create this method And Pass Array And Value:
- (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;
}
Another category method you could use:
- (NSArray *) filteredArrayUsingBlock:(BOOL (^)(id obj))block {
NSIndexSet *const filteredIndexes = [self indexesOfObjectsPassingTest:^BOOL (id _Nonnull obj, NSUInteger idx, BOOL *_Nonnull stop) {
return block(obj);
}];
return [self objectsAtIndexes:filteredIndexes];
}