Question

I have a history object with a url string property and title. I want to search all the history for objects with the url containing a search string, then remove all duplicates.

Example: I have an array of history objects and 20 of them are all "https://www.google.com" and 4 are "https://www.google.com/#q=search", I want to get an array back with only one object with the url value of "https://www.google.com" and one url value of "https://www.google.com/#q=search"

Here is my current code that searches the history and returns all objects matching the string:

    - (NSArray *)historyObjectsContainingQuery:(NSString *)query {
    NSMutableArray *matchingObjects = [[NSMutableArray alloc] init];
    HistoryManager *HM = [HistoryManager sharedInstance];
    for (int i=0; i<[[HM history] count]; i++) {
        //History "days"
        HistoryObject *historyItem = HistoryObject([[HistoryManager sharedInstance] history][i]);

        for (int o=0; o<[historyItem.objects count]; o++) {
            //Each object inn each history day
            HistoryObject *HO = HistoryObject(historyItem.objects[o]);
            if ([HO.title rangeOfString:query options:NSCaseInsensitiveSearch].location != NSNotFound) {
                //history objects with their title containing the query string
                [matchingObjects addObject:HO];
            }
        }
    }
    return matchingObjects;
}

Then i log each url value:

self.foundInBookmarksAndHistory = [self historyObjectsContainingQuery:textField.text]; for (HistoryObject *HO in self.foundInBookmarksAndHistory) { NSLog(@"%@",HO.url); }

and here is the results:

https://www.google.com/
2013-09-15 13:48:49.382 Flow HD[3599:60b] https://www.google.com/
2013-09-15 13:48:49.384 Flow HD[3599:60b] https://www.google.com/
2013-09-15 13:48:49.385 Flow HD[3599:60b] https://www.google.com/
2013-09-15 13:48:49.387 Flow HD[3599:60b] https://www.google.com/
2013-09-15 13:48:49.388 Flow HD[3599:60b] https://www.google.com/
2013-09-15 13:48:49.390 Flow HD[3599:60b] https://www.google.com/
2013-09-15 13:48:49.391 Flow HD[3599:60b] https://www.google.com/search?q=yahoo
2013-09-15 13:48:49.392 Flow HD[3599:60b] https://www.google.com/
2013-09-15 13:48:49.394 Flow HD[3599:60b] https://www.google.com/
2013-09-15 13:48:49.395 Flow HD[3599:60b] https://www.google.com/search?q=Sup
2013-09-15 13:48:49.397 Flow HD[3599:60b] https://www.google.com/
2013-09-15 13:48:49.398 Flow HD[3599:60b] https://www.google.com/
2013-09-15 13:48:49.400 Flow HD[3599:60b] https://www.google.com/
2013-09-15 13:48:49.402 Flow HD[3599:60b] https://www.google.com/
2013-09-15 13:48:49.404 Flow HD[3599:60b] https://www.google.com/
2013-09-15 13:48:49.405 Flow HD[3599:60b] https://www.google.com/

There is A LOT more, how can i remove each object with that same value? the objects are not equal, but do have equal urls.

I've tried NSPredicate and using more for loops to go through and find matching objects but im always left with 2 or more of the same objects with the same property.

Was it helpful?

Solution

You can do some thing like this :

NSMutableSet *seenObjects = [NSMutableSet set];
NSPredicate *dupPred = [NSPredicate predicateWithBlock: ^BOOL(id obj, NSDictionary *bind) {
    HistoryObject *hObj = (HistoryObject*)obj;
    BOOL seen = [seenObjects containsObject:hObj.title];
    if (!seen) {
        [seenObjects addObject:hObj.title];
    }
    return !seen;
}];
NSArray *yourHistoryArray = ... // This is your array which needs to be filtered
NSArray *yourHistoryArray = [yourHistoryArray filteredArrayUsingPredicate:dupObjectsPred];

OTHER TIPS

I'm not sure that's the best way to search all the objects but that aside the simplest fix I can think of for your code is to replace

if ([HO.title rangeOfString:query options:NSCaseInsensitiveSearch].location != NSNotFound) {
                [matchingObjects addObject:HO];
            }

with this:

if ([HO.title rangeOfString:query options:NSCaseInsensitiveSearch].location != NSNotFound) {
                HistoryObject *temp = HistoryObject(historyItem.objects[o]);
                [historyItem.objects removeObjectAtIndex:o];
            }

//And after all the `for` loops 

[historyItem.objects addObject:temp];

You removed all the matching objects and added it one time to the array.

Edit: After reading your edit, use isEqualToString instead of rangeOfString. rangeOfString will find the word abc in abcd, abce and abcf, that's not what you want. isEqualToString for abc will be valid only for abc and nothing else.

loop the mutable array ( change the array to mutable if necessary) if object still exists

while ([farray containsObject:_data]){
       [farray removeObject:_data];
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top