after a decent search and could not find solution (probably i missed something...):
i have an array with objects, the object is AddressCard and one if the properties is name.
so i send to my function string and with for statement looking all the matches inside my object collection array who contain AddressCArd object (bookArray) and if there is match i want to add this object to an array asnd return this array:
-(NSMutableArray *) lookup:(NSString *) name
{
NSMutableArray arr = [NSMutableArray array];
for(AddressCard *card in bookArray}
{
if([card.name rangeOfString: name].location == NSNotfound)
{
[arr addObject: card];
}
}
return arr;
}
You can do as this:
-(NSMutableArray *) lookup:(NSString *) name {
NSMutableArray *arr = [NSMutableArray array];
for(AddressCard *card in bookArray) {
//if([card.name isEqualToString:name]) {
if([[card.name capitalizedString] rangeOfString:[name capitalizedString]].location != NSNotFound)
[arr addObject:card];
}
}
return arr;
}
Related
I have an array of dictionaries with multiple keys and objects of different types. I want to fetch only one of the object and compare with the other object. I have been trying with for each loop but not bee able to do so.
Iterate the array:
for (NSDictionary *dict in array) {
then iterate the keys in the dictionary
NSArray *keys = [dict allKeys];
for (NSString *key in keys) {
then extract the value for the key:
id obj = dict[key];
Then test the object type and compare with the other object:
if ([obj isKindOfClass:[NSString class]]) {
NSString *stringObj = (NSString *)obj;
if ([stringObj isEqualToString:otherObj]) {
NSLog(#"Object equals dictionary entry %#", key);
}
} else if ([obj isKindOfClass:[NSNumber class]]) {
NSNumber *numberObj = (NSNumber *)obj;
if ([numberObj isEqual:otherObj]) {
NSLog(#"Object equals dictionary entry %#", key);
}
} else // etc.
first get the dictionary from array
NSDictionary *dict=[yourarray objectAtIndex:index];
then get the object from dictionary
NSString *yourValue=[dict objectForKey:#"Your KeyValue"];
In case of for each loop
for (NSDictionary *dict in yourArray) {
NSString *yourValue=[dict objectForKey:#"Your KeyValue"];
NSLog(#"%#",yourValue);
}
I'd like to do this without using NSSet. I know it's probably quicker but I'm trying to understand how arrays work. This is the mutable array I'm working with, it has duplicate values.
NSMutableArray *mainArray = #[#"a",#"a",#"b",#"c",#"d",#"d"];
NSLog(#"mainArray = %#", mainArray);
- (NSArray *)arrayWithUniqueObjectsFromArray:(NSArray *)array
{
NSMutableArray *uniqueObjects = [NSMutableArray new];
for(id obj in array) {
if([uniqueObjects containsObject:obj] == NO) {
[uniqueObjects addObject:obj];
}
}
return uniqueObjects;
}
I need a method that would add a few objects (2-10) to my array, skipping these that are nils:
NSMutableArray *arr = [[NSMutableArray alloc] init];
[arr addObjectsSkipNils:obj1, obj2, obj3];
How I can write this method in an elegant way?
This category method would work:
#interface NSMutableArray (MyAdditions)
- (void)addObjectsSkipNilsWithCount:(NSUInteger)count objects:(id)obj, ...;
#end
#implementation NSMutableArray (MyAdditions)
- (void)addObjectsSkipNilsWithCount:(NSUInteger)count objects:(id)obj, ...
{
va_list ap;
va_start(ap, obj);
// First object:
if (obj != nil)
[self addObject:obj];
// Remaining objects:
for (NSUInteger i = 1; i < count; i++) {
id myobj = va_arg(ap, id);
if (myobj != nil)
[self addObject:myobj];
}
va_end(ap);
}
#end
Example:
NSMutableArray *a = [NSMutableArray array];
[a addObjectsSkipNilsWithCount:3 objects:#"foo", nil, #"bar"];
NSLog(#"%#", a);
// Output: ( foo, bar )
You have to specify the number of objects explicitly, because nil cannot be used as terminator for the variable argument list. (And bad things can happen if the count is greater than the actual number of objects supplied !)
You can use:
[yourMainArray removeObjectIdenticalTo:[NSNull null]];
Now if you want to copy this to arr you can do quite easily.
I have filled a NSMutableArray with integer and string values from my database.
The problem is that many values were inserted more than once.
Using the following code I remove duplicate objects
for (id object in originalArray) {
if (![singleArray containsObject:object]) {
[singleArray addObject:object];
}
}
Bus this works only if the objects are exactly the same between them.
Is there a way to remove duplicates based on the integer value?
EDIT (from an OP's comment on a deleted answer)
I have some objects containing int and NSString. For example #"John 13", #"Mary 25", #"Luke 25", #"Joan 13". The NSMutableArray will contain all four names and duplicates of 13, 25. I want to remove the duplicates leaving 13 and 25 only once in the array. I do not care which names will be removed. Care only for the integer values to use them later.
If your elements are all NSNumber objects:
for (int i=0;i<array.count;i++) {
for (int j=i+1;j<array.count;j++) {
if ([array[i] isEqualToNumber:array[j]]) {
[array removeObjectAtIndex:j--];
}
}
}
Or if all objects are either integer NSNumbers or NSStrings containing integer values:
for (int i=0;i<array.count;i++) {
for (int j=i+1;j<array.count;j++) {
if ([array[i] intValue] == [array[j] intValue]) {
[array removeObjectAtIndex:j--];
}
}
}
Try this:
// singleArray is initially empty
for (id object in originalArray)
{
BOOL contains= YES;
for( id single in singleArray)
{
if( [single integerValue]==[object integerValue] )
{
contains= NO;
break;
}
}
if(contains)
{
[singleArray addObject: object];
}
}
no test, tell me if it does not work. assuming objects in the array are string and format is "WORD NUMBER"
Boolean myEqual(const void *value1, const void *value2) {
NSString *str1 = (__bridge NSString *)(value1);
NSString *str2 = (__bridge NSString *)(value2);
NSArray *arr1 = [str1 componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
NSArray *arr2 = [str2 componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
return [[arr1 lastObject] isEqual:[arr2 lastObject]];
}
CFHashCode myHash(const void *value) {
NSString *str1 = (__bridge NSString *)(value);
NSArray *arr1 = [str1 componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
return [[arr1 lastObject] hash];
}
NSMutableArray *array = // your array;
CFSetCallBacks callBacks = kCFTypeSetCallBacks;
callBacks.equal = myEqual;
callBacks.hash = myHash;
CFMutableSetRef set = CFSetCreateMutable(NULL, [array count], &callBacks);
for (id obj in [array copy]) { // copy so can modify the original array
if (CFSetContainsValue(set, (__bridge const void *)(obj))) {
[array removeObject:obj];
} else {
CFSetAddValue(set, (__bridge const void *)(obj));
}
}
I have been told that I can use NSPredicate to duplicate the results of this method
- (void) clearArrayOut
{
bool goAgain = false;
for (int j=0; j<[array count]; j++)
{
if ([[array objectAtIndex:j] someMethod] == NO)
{
[array removeObjectAtIndex:j];
goAgain = true;
break;
}
}
if (goAgain) [self clearArrayOut];
}
How can I make an NSPredicate that will filter an array based on the results of some method of a custom class's call?
To make a copy with the filter applied:
NSArray *filteredArray = [someArray filteredArrayUsingPredicate:
[NSPredicate predicateWithBlock:^(id object, NSDictionary *bindings) {
return [object someMethod]; // if someMethod returns YES, the object is kept
}]];
To filter an NSMutableArray in place:
[someMutableArray filterUsingPredicate:
[NSPredicate predicateWithBlock:^(id object, NSDictionary *bindings) {
return [object someMethod]; // if someMethod returns YES, the object is kept
}]];
But I would probably just use a for loop if I were filtering a small array. However, I'd write my for loop a little differently to avoid having to either decrement the index variable or call myself recursively:
- (void)clearArrayOut:(NSMutableArray *)array {
for (int i = array.count - 1; i >= 0; --i) {
if (![[array objectAtIndex:i] someMethod]) {
[array removeObjectAtIndex:i];
}
}
}
You simply write it into your predicate, for example, lets assume you have an object with a method called isOdd and you want to filter your array to include only objects that return true for isOdd, you can do this:
#import <Foundation/Foundation.h>
#interface barfoo : NSObject
{
int number;
}
- (BOOL)isOdd;
- (id)initWithNumber:(int)number;
#end
#implementation barfoo
- (NSString *)description
{
return [NSString stringWithFormat:#"%i", number];
}
- (BOOL)isOdd
{
return (number % 2);
}
- (id)initWithNumber:(int)tnumber
{
if((self = [super init]))
{
number = tnumber;
}
return self;
}
#end
int main(int argc, char *argv[]) {
#autoreleasepool {
NSMutableArray *array = [NSMutableArray array];
for(int i=0; i<10; i++)
{
barfoo *foo = [[barfoo alloc] initWithNumber:i];
[array addObject:[foo autorelease]];
}
NSLog(#"%#", array); // prints 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"isOdd == true"]; // This is oure predicate. isOdd must be true for objects to pass
NSArray *result = [array filteredArrayUsingPredicate:predicate];
NSLog(#"%#", result);
}
}
Of course this also works the other way around, your predicate could also read isOdd == false or you can add even more requirements for an object to pass. Eg isOdd == true AND foo == bar. You can read more about the NSPredicate syntax in the NSPredicate documentation.
Your implementation is terribly inefficient to start with: rather than continuing the deletions recursively, you could change your loop to not advance if an object has been deleted, like this:
- (void) clearArrayOut {
int j = 0;
while (j < [array count]) {
if ([[array objectAtIndex:j] someMethod] == NO) {
[array removeObjectAtIndex:j];
} else {
j++;
}
}
}
You could do the same thing using filterUsingPredicate:, like this:
- (void) clearArrayOut {
NSPredicate *p = [NSPredicate predicateWithBlock:^BOOL(id obj, NSDictionary *bindings) {
return [obj someMethod] == NO
}];
[array filterUsingPredicate:p];
}