My NSMutableArray contains the following data
<DoctorInfo: 0x15de99e0> (entity: DoctorInfo; id: 0x15defbe0 <x-coredata://39D9B/DoctorInfo/p8> ; data: {
doctorName = nil;
emailAdd = nil;
hospitalName = nil;
mobileNumber = nil;
phoneNumber = nil;
}),
<DoctorInfo: 0x15de9b00> (entity: DoctorInfo; id: 0x15da5dc0 <x-coredata://39D9BED3/DoctorInfo/p10> ; data: {
doctorName = nil;
emailAdd = nil;
hospitalName = nil;
mobileNumber = nil;
phoneNumber = nil;
})
)
How can I remove those objects with nil? I have tried the following code by changing NSMutableArray to the NSArray and then filter it but it is still not working:
NSString *predString = [NSString stringWithFormat:#"(doctorName BEGINSWITH[cd] '%#')", nil];
NSPredicate *pred = [NSPredicate predicateWithFormat:predString];
self.filteredDocInfoArray = [self.unfilteredDocInfoArray filteredArrayUsingPredicate:pred];
You test for nil in predicate strings like this:
NSPredicate *pred = [NSPredicate predicateWithFormat: #"doctorName = nil"];
See the documentation for examples.
You cannot add a nil object to array. In your case you are adding an object that has some nil properties!
You can try this:
[yourArr enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
DoctorInfo *customObj = obj;
if (customObj.doctorName) {
//add obj to temp array
}
}];
Now you can replace yourArr with tempArr
If you want to use NSPredicate, please refer this.
Related
In swift i am using this code to get particular object for a particular value
if let layer = self.layers.first(where: {$0.id == id}) { }
I want to use this same in objective-c. How should i get a object from array of objects for particular value
You can use NSPredicate in Objective-C to filter an array.
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"id == %#", id];
id layer = [[self.layers filteredArrayUsingPredicate:predicate] firstObject]
The predicateWithFormat solution is short, but not as type-safe as Swift.
To make it a bit more type-safe you could use indexOfObjectPassingTest.
Assuming you have:
#interface MyLayer
#property int layerID;
#end
NSArray<MyLayer *> *layers = #[...];
int layerIDToFind = 123;
You can write:
NSUInteger index = [layers indexOfObjectPassingTest:^BOOL(MyLayer *layer, NSUInteger idx, BOOL *stop) {
return layer.layerID == layerIDToFind;
}];
if (index != NSNotFound) {
MyLayer *layer = layers[index];
// ... act on the layer ...
}
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"id == %#", id];
NSArray *result = [self.layers filteredArrayUsingPredicate:predicate];
if result.count > 0
{
id layer = [result firstObject].id
}
i have a JSON Dict in this format
{
"382" : "sudhir kumar",
"268" : "David ",
"385" : "aayush test",
"261" : "Mike watson",
"277" : "TestDrivers Driver",
"381" : "sudhir kumar",
"380" : "sudhir kumar",
"383" : "asdfgh asdfgh",
"376" : " "
}
I have to display it in UISearchBar. Someone please help me to solve it as when i select any name from search its respective Id also selected
I am using the following code it filtered name but not their related ID's with name
My code is:
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText;
{
tempArray = [NSArray arrayWithArray:DriverNameArray];
//NSString *stringToSearch = textField.text;
tempId = [NSArray arrayWithArray:DriverIdArray];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF BEGINSWITH[c] %#",searchText]; // if you need case sensitive search avoid '[c]' in the predicate
//NSPredicate * predicateid = [NSPredicate predicateWithFormat:#"SELF BEGINSWITH[c] %#",stringToSearch];
NSArray *tempresults = [DriverNameArray filteredArrayUsingPredicate:predicate];
if (tempresults.count > 0)
{
tempArray = [NSArray arrayWithArray:tempresults];
tempId = [NSArray arrayWithArray:tempresults];
}
[SEarchTable reloadData];
//return YES;
}
It always returns the same id for all the filtered names
Create NSarray of NSdictionary containing id and name
MasterArray :
(
0{ id = "382" , drivername = "sudhir kumar"}
1{ id = "383" , drivername = "sudha mishra"}
.
.
n{ id = "384" , drivername = "sudesh pandit"}
)
whatever search result you will get in Your DriverNameArray. Iterate for loop through that and compare driver name with MasterArray
:
for(i = 0; i< DriverNameArray.count , i++)
{
//take driver name from search result array
NSString * driverName = [DriverNameArray objectAtIndex:i];
for(j = 0; j< MasterArray.count , j++){// search driver name in MasterArray
NSDictionary *driverInfoDic = [MasterArray objectAtIndex:j];
if(driverName isEqualToString:[driverInfoDic objectForKey:#"drivername"])
NSString *driverId = [driverInfoDic objectForKey:#"Id"];//use this driver id by storing it in DiverIdArray
}
}
You are filtering only Drivers' names array, which is not primarily connected with Drivers' ids array. I suggest you joining id, and name into a dictionary and storing it in one array. So that, whenever you filter it with name, or id the rest info will be stored in one object
#property (nonatomic, strong) NSMutableArray *allElements
#property (nonatomic, strong) NSArray *filteredArray;
`
for (int i=0; i < 10; i++) { //Just simple example
NSDictionary *dictionary = #{#"name": DriverNameArray[i], #"id": DriverIdArray[i] };
[self.allElements addObject:dictionary];
}
And in your searchbar delegate you can use:
NSArray *copyArray = [self.allElements copy];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"name BEGINSWITH %#", searchText];
NSArray *filteredArray = [copyArray filteredArrayUsingPredicate:predicate];
self.filteredArray = filteredArray;
[self.tableView reloadData];
I have an NSArray. It has one or more NSDictionary in each index. Based on the search input, I want to check whether it contain the value in contact_Label inside contact_detail dictionary. It will look like this:
(
{
"contact_detail" = {
"contact_is_in_phone" = 1;
"contact_Label" = "Tyler Globussoft";
"contact_displayname" = "Suzan Arohh";
},
"last_msg_details" = {
.....
};
},
{
}
);
I have tired like this. But not getting the result.
NSArray *contacts = self.dataArray; //your array of NSDictionary objects
NSPredicate *filter = [NSPredicate predicateWithFormat:#"contact_Label = %#",stringValue];
NSArray *filteredContacts = [contacts filteredArrayUsingPredicate:filter];
You can use
NSArray *contacts = self.dataArray; //your array of NSDictionary objects
NSPredicate *filter = [NSPredicate predicateWithFormat:#"contact_detail.contact_Label = %#",stringValue];
NSArray *filteredContacts = [contacts filteredArrayUsingPredicate:filter];
Happy coding...
Hello I have a NSMutableArray like this
Contactarray (
{
"firstNAme"="name1"
"lastName"="name2"
"phoneNumber"="12345678902";
}
{
"firstNAme"="name1"
"lastName"="name2"
"phoneNumber"="12345678902";
}
I want to search the person when I type the person name in my UITextField. Then the filtered UItableView should be loaded. This NSMutableArray contains NSMutableDictionaries.
How can I find the matching object from these objects?
Lets say I want to search all name1 people. Then I want to find all the objects containing "name1" and those objects should fill to another array to load the UITableview
Please help me.
Thanks.
UPDATE
This is my contacts array
<__NSArrayI 0x7b601f70>(
firstname = Kate;
lastName = Bell;
phone = "(415) 555-3695";
userimg = "<UIImage: 0x7b67b3a0>";
};
{
firstname = Kate;
lastName = Bell;
phone = "(415) 555-3695";
userimg = "<UIImage: 0x7b67b3a0>";
},
This is my code for search
`
[playlistArray removeAllObjects];
NSArray *contacts=[[NSArray alloc] initWithArray:mutArraySearchContacts];
NSPredicate *filter = [NSPredicate predicateWithFormat:#"firstname = %# OR lastName = %#",currentSrchStr,currentSrchStr];
playlistArray=[contacts filteredArrayUsingPredicate:filter];
[self performSelectorInBackground:#selector(playlistsLoaded) withObject:nil];
`
But my playlistArray is empty.
`
(lldb) po playlistArray
<__NSArrayI 0x7b74adf0>(
)
`
What is the wrong I have done here?
No need to iterate while you use NSPredicate. Try this.
NSPredicate * myPredicate = [NSPredicate predicateWithFormat:[NSString stringWithFormat:#"SELF['firstNAme'] contains '%#' || SELF['lastName'] contains '%#'",currentSrchStr,currentSrchStr]];
NSArray *filterArray = [mutArraySearchContacts filteredArrayUsingPredicate:myPredicate];
NSLog(#"filterArray %#", filterArray);
Update 1:
Modify your predicate with CONTAIN[C] for case insensitive, like
NSPredicate * myPredicate = [NSPredicate predicateWithFormat:[NSString stringWithFormat:#"SELF['firstNAme'] CONTAINS[c] '%#' || SELF['lastName'] CONTAINS[c] '%#'",currentSrchStr,currentSrchStr]];
Hope this helps you !!
NSArray *contacts = ...; //your array of NSDictionary objects
NSPredicate *filter = [NSPredicate predicateWithFormat:[NSString stringWithFormat:#"firstName == %#", #"name1"]];
NSArray *filteredContacts = [contacts filteredArrayUsingPredicate:filter];
If you need to search with more condition, like full name:
NSPredicate *filter = [NSPredicate predicateWithFormat:[NSString stringWithFormat:#"firstName == %# OR lastName == %#" ,#"name1", #"name2"]];
Here is Predicate Programming Guide, which illustrates more advanced features.
You can use keysOfEntriesPassingTest: method to find all keys where the value equals #"test".
In the implementation below only the first key will be found. If you need all keys where the object is #"Test", do not assign *stop.
NSString *target = #"test";
NSSet *keys = [myDictionary keysOfEntriesPassingTest:^(id key, id obj, BOOL *stop)
{
return (*stop = [target isEqual:obj]);
}];
when u get the key you can proceed further.
I have an array of combinations which needs to be searched in another array of dictionaries
Array Of Dictionaries is as follows:
self.listOfAllContacts
({
name = "William";
recordId = 541;
},
{
name = "Soan";
recordId = 541;
},
{
name = "kamal";
recordId = 541;
},
{
name = "Elisia";
recordId = 541;
},
{
name = "Ben";
recordId = 541;
},
{
name = "Loki";
recordId = 541;
},
{
name = "Fraser";
recordId = 541;
});
Array Of Combinations are as follows : array named as
self.arrayOfSearchCombinationsFormed
<__NSArrayM 0x1702518b0>(
ABCD,
JK,
AND,
MIKE,
ELI,
STEV,
FRASE,
WIILIA
)
Present Code in work:
self.filteredContacts = [[NSMutableArray alloc] init];
NSArray *arrayToTraversed = [[NSArray alloc] initWithArray:self.arrayOfSearchCombinationsFormed];
for(NSString *combination in arrayToTraversed){
NSPredicate *predicateInsideLoop = [NSPredicate predicateWithFormat:#"name CONTAINS[cd] %#", combination];
NSArray *filteredContactByName = [self.listOfAllContacts filteredArrayUsingPredicate:predicateInsideLoop];
if([filteredContactByName count]>0){
[self.filteredContacts addObjectsFromArray:filteredContactByName];
}
else{
[self.arrayOfSearchCombinationsFormed removeObject:combination];
}
}
Presently this solution is inefficient and consuming a lot of memory.
Any help would be appreciated.
Also note that any combination not found in the dictionary needs to be removed from the combinations array.
So my question is that i want the most efficient way of searching the names in terms of memory allocation. So that it uses minimum memory.
It might be helpful to use (NSPredicate*)predicateWithBlock: method to speed up searching.
Suppose you have a keys array and a source array, you want to filter the source array with the keys array.
NSArray *keysArray = #[#"1",#"2",#"3"];
NSArray *sourceArray = #[#"12",#"2",#"3",#"1",#"2"];
For the first object #"12" in sourceArray, looking at the keysArray, since #"12" contains #"1", you can stop filtering and keep the first object of both arrays. But original code uses #"1" to filter the sourceArray, result is #"12" and #"1", each element needs to be checked.
You can refer to the below code:
- (void)searchWithBlock:(NSArray*)keysArray
{
NSDate *beginDate = [NSDate date];
NSMutableSet *keySet = [NSMutableSet set];
NSPredicate *intersectPredicate = [NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) {
for (NSString *str in keysArray) {
NSString *name = evaluatedObject[#"name"];
NSRange r = [name rangeOfString:str options:NSCaseInsensitiveSearch];
if (r.location != NSNotFound) {
[keySet addObject:str];
return true;
}
}
return false;
}];
NSArray *intersect = [self.listOfAllContacts filteredArrayUsingPredicate:intersectPredicate];
self.filteredContacts = [[NSMutableArray alloc] initWithArray:intersect];
self.arrayOfSearchCombinationsFormed = [NSMutableArray arrayWithArray:[keySet allObjects]];
NSDate *endDate = [NSDate date];
NSTimeInterval interval = [endDate timeIntervalSinceDate:beginDate];
NSLog(#"interval is %f",interval);
NSLog(#"intersect %#\n, filtered key array is %#\n", intersect,keySet);
}
It needs about 1/3 of the original time for filtering, memory allocation is a little bit less. I suggest you split the larger data source to smaller chunks to use less memory.
This should do the trick:
NSString *sourceRegexp =
[NSString stringWithFormat:#".*%#.*",
[combinations componentsJoinedByString:#".*|.*"]];
NSPredicate *sourcePredicate =
[NSPredicate predicateWithFormat:#"name MATCHES[c] %#", sourceRegexp];
NSArray *filteredSource =
[source filteredArrayUsingPredicate:sourcePredicate];
NSPredicate *combinationsPredicate =
[NSPredicate predicateWithFormat:
#"SUBQUERY(%#, $s, $s.name CONTAINS[c] SELF).#count > 0",
filteredSource];
NSArray *filteredCombinations =
[combinations filteredArrayUsingPredicate:combinationsPredicate];
I may have misunderstood the question, but wouldn't using an NSPredicate with a set work?
NSSet *contactsToSearchFor = [NSSet setWithArray:self.arrayOfSearchCombinationsFormed];
NSPredicate *prediate = [NSPredicate predicateWithFormat:#"name IN[cd] %#", contactsToSearchFor];
NSArray *results = [self.listOfAllContacts filteredArrayUsingPredicate:predicate];
I haven't tested this in XCode, but it should work.
Why not implement a binary search algorithm to search array.
The link provided below gives you full details on how to implement binary search.
See: http://oleb.net/blog/2013/07/nsarray-binary-search/
I would recommend you to use swift for this purposes: it is much faster and allocates much less memory. Here is a solution in Swift:
func filterContacts(contacts: [Dictionary<String, String>], searchCombinations: [String]) -> [Dictionary<String, String>]{
return contacts.filter { dict in
let name = dict["name"]!
for string in searchCombinations{
if name.rangeOfString(string) != nil { return true }
}
return false
}
}
Another much more complex solution would involve using Suffix Tree for storing your contacts data if duration of searching is important.