Getting distinct rows from Realm table in iOS - ios

I am using Realm database for iOS application where i have a use case in which i want to filter result set by distinct values for a particular field. This field is not a primary key of the realm table.
I was not able to construct query for that.
Sample query :
RLMResults *allFiles = [FileRLMObject objectsInRealm:realmObject where:#"colA == %#", #"test1"];
FileRLMObject is a subclass of RLMObject from realm library
here table contains one column with name colB. While getting allFiles results, i want to get rows which are having distinct colB values.
Any suggestions how i can achieve this?

Realm doesn't support distinct queries yet. You can subscribe issue #1103 to track progress on that.
As a workaround, you could query for all values for colB first and then select objects for each value of it, as seen below:
NSArray *values = [FileRLMObject.allObjects valueForKey:"type"];
NSSet *distinctValues = [NSSet setWithArray:values];
NSMutableArray *allFiles = [NSMutableArray new];
for (NSString *colB in distinctValues) {
// This takes the firstObject.
// You might want to modify the sort order to make sure
// you get a certain object in case that there may exist
// multiple objects per distinct value.
FileRLMObject *object = [FileRLMObject objectsWhere:#"colB == ?", colB].firstObject;
[allFiles appendObject:object];
}

Related

IOS/Objective-C: Search string element with array of objects

As part of an autocomplete box, I am searching names within an array of contacts. However, after the user picks a name from the suggested List, I need to grab the id of the contact which is in the array of contact objects but not the array of names that appear in the suggest box. I've been working with just the names as that's what I want to display in the suggestion box but have an array of contacts as well.
How would I convert code below (probably using key values) to search the name dimensions of an array of objects instead of an array of names so as to keep track of the ids of the objects. I am kind of fuzzy on arrays and key values.
//the array being searched looks something like #[#"John", #"Dave", #"Sam", #"Xian", #"Ahmed", #"Johann"];
//I want to search the names in an array that looks something like:
(
{
first = "John";cid = 2;},
{
first = "Dave";cid = 44;},
{
first = "Xian";cid=99})
//this code works great to search names but I lose track ids. Thank you for any suggestions.
-(void)searchArray: (NSMutableArray*) array forString: (NSString *) term {
[_contactsSuggested removeAllObjects];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF contains[c] %#",term];
NSArray *tempArray = [array filteredArrayUsingPredicate:predicate];
_contactsSuggested = [NSMutableArray arrayWithArray:tempArray];
[_autocompleteTableView reloadData];
}
Create a Contact object. Give it a name property, an id property, and any other properties you need. Then write code that searches an array of Contact objects rather than just an array of names. You could then create a predicate using predicateWithBlock to filter the items that match your name property.

Fetch Realm objects that contain parameter

I have a realm database filled with Restaurant objects that have a url parameter. I'd like to fetch the objects where the url contains what the user has typed in a UITextField.
NSPredicate *pred = [NSPredicate predicateWithFormat:#"url CONTAINS '%#'", self.searchQuery];
RLMResults<Database *> *results = [Database objectsWithPredicate:pred];
if ([results count] == 0) {
NSLog(#"results count == 0");
return nil;
}
Now, when I run this, I always get 0 results. Eventhough I have two example entries that have 'http://www.testingthis.com' as an url and the search query is 'testingthis'. Any ideas as to why I'm not getting results?
You need to perform your search query against the Restaurant class itself; not Database. Realm uses the class you specify to determine which table in which to apply the query.
As an aside, you can also inline NSPredicate queries with +[RLMObject objectsWhere:], so it's not necessary to create a separate NSPredicate object (unless you've got a specific reason). :)
RLMResults *restaurants = [Restaurant objectsWhere:#"url CONTAINS '%#'", #"testingthis"];
If you're trying to query for Restaurant objects that aren't in the default Realm, then you can alternatively use +[RLMObject objectsInRealm: where:] to explicitly control which database you're querying.

Nested core data fetch

I have a core data DB with multiple entities. There is a parent entity called "Person" which has many "Friends", "Friends" have many "Activities", and "Activities" have "Types" ("Types has a to-many relationship to "Activities"). What I'm trying to achieve is filtering all the "Person" entities by "Types". A user would be tapping on a "Type" and then I would refresh my table and filter the "Person" entities that are displayed by the "Types" that are associated with them.
Currently I'm thinking I have to use a compound predicate but I'm completely sure how to go about it. So far all I've done is printed out the values I've wanted by looping through my fetchedObjects like so:
NSArray *persons = self.fetchedResultsController.fetchedObjects;
for (JIPerson *person in persons) {
JIFriend *friend = person.friends.anyObject;
JIActivity *activity = friend.activities.anyObject;
JIType *type = activity.type;
NSLog(#"%#", type.name);
}
This prints out the values correctly, but I need to filter my table using these values. How can I achieve that?
Seems like I got it. Using NSPredicate you can traverse a deep relationship like this using dot notation. My implementation went as follows:
- (void)filterPersonByType:(NSString *)typeName {
NSPredicate *typePredicate = [NSPredicate predicateWithFormat:#"ANY friends.activities.type.name CONTAINS[cd]%#", typeName];
}
Yes, you can use dot notation with NSPredicate. You might want to have the type be an actual type, though, that would be cleaner than just doing string comparisons.

Non-relative NSArray sort

I want to sort an NSArray of NSStrings by similarity to a single given string, as opposed to relative sort order for items within the array.
Or to put it a different way, I want to sort the array by comparing all the items contained in the array by similarity to a single item, not sort them by comparing each other.
I have the logic for similarity figured out, it's just how I use the NSArray and/or NSSortDescriptor APIs to achieve this.
sortedArrayUsingComparator should allow you to achieve this ...
NSArray* sourceArray = //... your data
NSString* itemToCompareTo = sourceArray[5]; // locate the item you want to compare to
NSArray* sortedArray = [listItem sortedArrayUsingComparator: ^(id a, id b) {
// compare a, b, and itemToCompareTo here, using your sort logic
}

NSMutableArray or NSMutableDictionary : which is best for this scenario?

I need to scroll through several thousands of words to categorize them... to determine which words have the same pattern. (this part works)
For example, a four letter word that has two m's in 2nd & 4th position represent a pattern ("-m-m"). Once I have gone through all the words, I will know how many words there are for any given pattern. I am scrolling through now, but the problem I have is 'remembering' how many words I have in any given pattern.
I was thinking of using NSMutableDictionary and have the key be the pattern ('-m-m-') and the object represent the count of that pattern. This means every time I come across a pattern, I look up that pattern in the dictionary, get the key, increment the key, and put it back in the dictionary.
I need help with both the decision and syntax for performing this task.
Thank You
The answer to your question was this part of your (given) question "I will know how many words there are for any given pattern.". I would use an array of dictionary. You use the dictionary to store key value pair: a known pattern and the count. And you use the array to store those KVP records. So the next time you detect a pattern, search for the array for that record (dictionary), if found, increment the count. If not, create new record and set the count to 1.
Added sample code:
#define kPattern #"Pattern"
#define kPatternCount #"PatternCount"
-(NSMutableDictionary *)createANewDictionaryRecord:(NSString *) newPattern
{
int count = 1;
NSMutableDictionary *myDictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys:
newPattern, kPattern,
[NSString stringWithFormat:#"%i",count], kPatternCount,
nil];
return myDictionary;
}
-(void)addANewPatternToArray:(NSMutableDictionary *)newDictionary
{
// NSMutableArray *myArrayOfDictionary = [[NSMutableArray alloc]init]; // you need to define it somewhere else and use property etc.
[self.myArrayOfDictionary addObject:newDictionary]; //or [self.myArrayOfDictionary addObject:newDictionary]; if you follow the recommendation above.
}
-(BOOL)existingPatternLookup:(NSString *)pattern
{
for (NSMutableDictionary *obj in self.myArrayOfDictionary)
{
if ([[obj objectForKey:kPattern] isEqual:pattern])
{
int count = [[obj objectForKey:kPatternCount] intValue] + 1;
[obj setValue:[NSString stringWithFormat:#"%i",count] forKey:kPatternCount];
return YES;
}
}
[self.myArrayOfDictionary addObject:[self createANewDictionaryRecord:pattern]];
return NO;
}
-(void)testData
{
NSMutableDictionary *newDict = [self createANewDictionaryRecord:#"mmm"];
[self addANewPatternToArray:newDict];
}
-(void) printArray
{
for (NSMutableDictionary * obj in self.myArrayOfDictionary)
{
NSLog(#"mydictionary: %#", obj);
}
}
- (IBAction)buttonPressed:(id)sender
{
if ([self existingPatternLookup:#"abc"])
{
[self printArray];
} else
{
[self printArray];
}
}
Not being an objective C expert but solving this problem in java before, I would say a dictionary(I used a map when doing it in java) is the best way. Check if the key(pattern) already exist if so increment that count else put a new one in the dictionary.
EDIT
If you want to not just get the count of a pattern, but in fact tell which words fall under that pattern, I would use a dictionary of strings to mutable arrays. In the arrays you store the words and the key to the array is the pattern(as a string), similar code as above but instead of just incrementing the count, you have to add the new word to the array.
The only difference in NSDictionary and NSMutableDictionary is that one can have objects added to it. I think your implementation is good, but English is a complex language. It would be more efficient to parse out the string with regex than to set a key for it.
Why don't you use NSCountedSet instead:
NSCountedSet Class Reference
..which is available in iOS 2.0 and later?
Each distinct object inserted into an NSCountedSet object has a counter associated with it. NSCountedSetkeeps track of the number of times objects are inserted [...] Thus, there is only one instance of an object in an NSSet object even if the object has been added to the set multiple times. The count method defined by the superclass NSSet has special significance; it returns the number of distinct objects, not the total number of times objects are represented in the set.
Then use:
- (NSUInteger)countForObject:(id)anObject
Use a dictionary of NSMutableArrays, and check for the existence of each search key as you recommended. If the key doesn't exist, add an NSMutableSet or NSMutableArray (depending on your needs) for the searched key type "-m-m" for example, and then add to the set or array for that key.

Resources