find element inside array of dictionaries for a given value - objective-c

I have two NSArray variables, each one of then gets a similar NSDictionary inside.
For a given row (indexPath.row):
NSArray* array1 = ...;
NSDictionary* item = [array1 objectAtIndex:indexPath.row];
int myid = [[item valueForKey:#"id"] intValue];
// id = 5
Now I need to find the element with id = 5 in array2, but because I'm a c# developer, I think it is a little weird to use a for to do that.
Is there any alternatives to a for?

NSArray has a method indexOfObjectPassingTest which you can use:
NSArray *array2 = ...;
int searchId = ...;
NSUInteger index2 = [array2 indexOfObjectPassingTest:^BOOL(NSDictionary *item, NSUInteger idx, BOOL *stop) {
BOOL found = [[item objectForKey:#"id"] intValue] == searchId;
return found;
}];
if (index2 != NSNotFound) {
// First matching item at index2.
} else {
// No matching item found.
}
This returns the first matching index. If you need all matching indexes, use indexesOfObjectsPassingTest.

Related

How can i count and sort a NSMutableArray duplicate values

I've seen this question:
NSMutableArray counting occurances of objects and then re-arange the array
The solution comes very close to what i need.
The solution I'm referring to:
NSInteger countedSort(id obj1, id obj2, void *context) {
NSCountedSet *countedSet = context;
NSUInteger obj1Count = [countedSet countForObject:obj1];
NSUInteger obj2Count = [countedSet countForObject:obj2];
if (obj1Count > obj2Count) return NSOrderedAscending;
else if (obj1Count < obj2Count) return NSOrderedDescending;
return NSOrderedSame;
}
and:
NSMutableArray *array = …;
NSCountedSet *countedSet = [[[NSCountedSet alloc] initWithArray:array]
autorelease];
[array sortUsingFunction:countedSort context:countedSet];
The sort returns proper sorted array by count, but i need the count either included or in another array sorted ascending.
A solution could be to simply query the counted set for the count of any object, to build an array that keep track of the counts:
// This after having sorted the array:
NSMutableArray* counts= [NSMutableArray arrayWithCapacity: array.count];
for(id object in array) {
[counts addObject: #([countedSet countForObject: object]) ];
}
This return a sorted array ordered by the most occurring value
NSCountedSet *countedSet = [[NSCountedSet alloc] initWithArray:array];
NSArray *sortedValues = [countedSet.allObjects sortedArrayUsingComparator:^(id obj1, id obj2) {
NSUInteger n = [countedSet countForObject:obj1];
NSUInteger m = [countedSet countForObject:obj2];
return (n <= m)? (n < m)? NSOrderedDescending : NSOrderedSame : NSOrderedAscending;
}];

Searching for a string within an array for an NSRange

I am trying to search for a string within an array, but I only want to search the last five objects in the array for the string.
I have been fiddling with every parameter I can find on NSRange to no avail.
I would post some example code, but I can't even get out the line I need, whether its through introspection, enumeration, or just some NSRange call that I missed.
If your array elements are strings that you searched for, you can directly check the array as follows:
if ([yourArray containsObject:yourString])
{
int index = [yourArray indexOfObject:yourString];
if (index>= yourArray.count-5)
{
// Your string matched
}
}
I like indexesOfObjectsWithOptions:passingTest: for this. Example:
NSArray *array = #[#24, #32, #126, #1, #98, #16, #67, #42, #44];
// run test block on each element of the array, starting at the end of the array
NSIndexSet *hits = [array indexesOfObjectsWithOptions:NSEnumerationReverse passingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
// if we're past the elements we're interested in
// we can set the `stop` pointer to YES to break out of
// the enumeration
if (idx < [array count] - 5) {
*stop = YES;
return NO;
}
// do our test -- if the element matches, return YES
if (40 > [obj intValue]) {
return YES;
}
return NO;
}];
// indexes of matching elements are in `hits`
NSLog(#"%#", hits);
Try this :-
//Take only last 5 objects
NSRange range = NSMakeRange([mutableArray1 count] - 5, 5);
NSMutableArray *mutableArray2 = [NSMutableArray arrayWithArray:
[mutableArray1 subarrayWithRange:range]];
//Now apply search logic on your mutableArray2
for (int i=0;i<[mutableArray2 count];i++)
{
if ([[mutableArray2 objectAtIndex:i] isEqualToString:matchString])
{
//String matched
}
}
Hope this helps you!

loop through array of dictionaries to find a value

I have an array of dictionaries that I would like to go through to find a matching value that I can then Count == Nth item of the array
Each item of the array looks like this
HMOD = 0;
MID = 39;
MOD = SOMETHING; // looking for this value
ID = 50;
So I would like to create a loop that goes through the array until it finds the matching value, then I use the number in the count as an reference to Index path in the next view..
I have written this peice of code which dosnt work... but hopefully it gives you an idea of the loop I am trying to create.
int count = 0;
while (singleName != [[ModArray valueForKey:#"MOD"] objectAtIndex:count]) {
count ++;
NSLog(#"%i", count);
}
SingleName is a NSString that I am using to match the MOD value in ModArray...
Any help would be greatly appreciated.
Here is a simpler solution by using valueForKey on the array of dictionaries,
Assuming that your modArray is like this,
NSArray *modArray = [NSArray arrayWithObjects:[NSDictionary dictionaryWithObject:#"0" forKey:#"HMOD"],
[NSDictionary dictionaryWithObject:#"39" forKey:#"MID"],
[NSDictionary dictionaryWithObject:#"something" forKey:#"MOD"],
[NSDictionary dictionaryWithObject:#"50" forKey:#"ID"], nil];
And singleName has a value as "something"
NSString *singleName = #"something";
Fetch the array from modArray which has an object with key as "MOD",
NSArray *array = [modArray valueForKey:#"MOD"];
Check if singleName is present in this array. If yes, then get the first index of that object which will be same as the index of dictionary with key "MOD" in modArray.
if ([array containsObject:singleName]) {
NSLog(#"%d", [array indexOfObject:singleName]);
} else {
NSLog(#"%# is not present in the array", singleName);
}
Update:
If you want to do it in your way, only mistake was you were using != whereas you should have used isEqualToString. You should have done like this,
int count = 0;
while (![singleName isEqualToString:[[modArray valueForKey:#"MOD"] objectAtIndex:count]]) {
count ++;
NSLog(#"%i", count);
}
Your code looks all inside out. You state you have an array of dictionaries. Assuming ModArray is the array (based on the name) you might do this:
NSUInteger count = 0;
for (NSDictionary *dict in ModArray) { // iterate through the array
NSString *mod = dict[#"MOD"]; // get the value for MOD
if ([mod isEqualToString:singleName]) { // compare the two strings
break; // they match so exit the loop
}
count++
}
// count has the index of the dictionary with the matching MOD value
Edit: Based on ACB correcting my misunderstanding of NSArray valueForKey:, the only real issue is your use of using != to compare the two strings.
- This is Helpful when you search from Dictionary.
NSMutableArray *contentList;
NSMutableArray *filteredContentList;
BOOL isSearching;
// firstSection is array which already filled.
// contentList array for value of particular key
// filteredContentList is search array from actual array.
- (void)searchTableList {
NSString *searchString = searchBar.text;
NSPredicate *filterPredicate = [NSPredicate predicateWithFormat:#"frame_code beginswith[c] %#", searchString];
NSArray *filteredArr = [firstSection filteredArrayUsingPredicate:filterPredicate];
if(contentList.count > 0)
[contentList removeAllObjects];
[filteredContentList addObjectsFromArray:filteredArr];
}
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar1 {
if ([searchBar1.text length] != 0)
isSearching = YES;
else
isSearching = NO;
}
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
NSLog(#"Text change - %d",isSearching);
//Remove all objects first.
[filteredContentList removeAllObjects];
if([searchText length] != 0) {
isSearching = YES;
[self searchTableList];
}
else {
isSearching = NO;
}
[tblFrameList_SComplete reloadData];
}
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
NSLog(#"Cancel clicked");
}
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
NSLog(#"Search Clicked");
[self searchTableList];
}

How do I compare if *ALL* strings of a NSArray are equal ?

How do I compare if all strings of a NSArray are equal ?
Should I scan the array for each string ?
thanks
You could do this by creating a new set from the array. The set will only contain unique entries so if the number of elements in the set is 1 then all items in the array was equal.
NSSet *uniqueItems = [NSSet setWithArray:yourArray];
if ([uniqueItems count] < 2) {
// All items in "yourArray" are the same (no matter how many they are)
}
In the above example I'm considering an empty set (meaning an empty array) as a being unique as well. If you don't then you can change the if-statement to if ([uniqueItems count] == 1) { ... }
This will also work for any object, not just strings.
The NSArray class is general-purpose so it won't contain functionality to perform this, so yes, you'll have to check each string yourself.
trojanfoe is right. You can enhance NSArray with category and do something like this ...
NSArray *array = #[ #"A", #"B", #"C" ];
__block BOOL allObjectsAreEqual = YES;
if ( array.count > 1 ) {
NSString *firstObject = array[0];
[array enumerateObjectsUsingBlock:^void(id obj, NSUInteger idx, BOOL *stop) {
if ( idx == 0 ) {
return;
}
if ( ( allObjectsAreEqual = [firstObject isEqualToString:obj] ) == NO ) {
*stop = YES;
}
}];
// And here check for allObjectsAreEqual ...
... there're many ways how to do this.
Are you wanting to check whether all the strings are equal to each other?
#interface NSArray (MyAdditions)
- (BOOL) isFilledWithEqualObjects {
if (!self.count) return YES;
id firstObject = [self objectAtIndex:0];
for (id obj in self) {
// Avoid comparing firstObject to itself (and any other pointers to
// firstObject)
if (firstObject == obj) continue;
if (![firstObject isEqual:obj]) return NO;
}
return YES;
}
#end
That example uses -isEqual:, to work with any kind of object. If you know the contents are strings, you can use -isEqualToString: instead:
if (![firstObject isEqualToString:obj]) return NO;

NSMutableArray removeObjectAtIndex usage

I am trying to filter out an array of strings based on their length. I'm completely new to Objective C and OOP in general.
wordList=[[stringFile componentsSeparatedByCharactersInSet:[NSCharacterSetnewlineCharacterSet]] mutableCopy];
for (int x=0; x<[wordList count]; x++) {
if ([[wordList objectAtIndex:x] length] != 6) {
[wordList removeObjectAtIndex:x];
}else {
NSLog([wordList objectAtIndex:x]);
}
}
for (int x=0; x<[wordList count]; x++) {
NSLog([wordList objectAtIndex:x]);
}
The NSLog in the else statement will only output 6 letter words, but the second NSLog outputs the entire array. What am I missing here? Also any general pointers to clean up/improve the code are appreciated.
Depending on what you feel is the easiest to understand you could either filter the array with a predicate or iterate over the array and remove objects. You should chose the approach that you have easiest to understand and maintain.
Filter using a predicate
Predicates are a very concise way of filtering array or sets but depending on your background they may feel strange to use. You could filter your array like this:
NSMutableArray * wordList = // ...
[wordList filterUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) {
NSString *word = evaluatedObject;
return ([word length] == 6);
}]];
Enumerating and removing
You cannot modify the array while enumerating it but you can make a note of all the items what you want to remove and remove them all in a batch after having enumerated the entire array, like this:
NSMutableArray * wordList = // ...
NSMutableIndexSet *indicesForObjectsToRemove = [[NSMutableIndexSet alloc] init];
[wordList enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSString *word = obj;
if ([word length] != 6) [indicesForObjectsToRemove addIndex:idx];
}];
[wordList removeObjectsAtIndexes:indicesForObjectsToRemove];
The problem with your code is that when you remove an item at index x and move to the next index x++, the item that was at x+1 is never examined.
The best way of filtering a mutable array is using the filterUsingPredicate: method. Here is how you use it:
wordList=[[stringFile
componentsSeparatedByCharactersInSet:[NSCharacterSetnewlineCharacterSet]]
mutableCopy];
[wordList filterUsingPredicate:
[NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary * bindings) {
return [evaluatedObject length] == 6; // YES means "keep"
}]];