Replace an Dictionary object in Array using NSPredicate - ios

I have one dictionary object in Array.
I want to replace this object with new dictionary.
Both have same order_id.
Currently I am doing it like, How can I do it with NSPredicate.
NSMutableArray *orderList=[[NSUserDefaults standardUserDefaults] objectForKey:#"Orders"];
//2. Find and replace the object/OrdeDetails.
for(int i=0;i<orderList.count;i++){
NSDictionary *dictionary=orderList[i];
if([dictionary[#"order_id"] isEqualToString:OrderDetails[#"order_id"]]){
[orderList replaceObjectAtIndex:i withObject:OrderDetails];
break;
}
}

Check this code:
NSPredicate *resultPredicate = [NSPredicate
predicateWithFormat:#"SELF.order_id contains[cd] %#",OrderDetails[#"order_id"]];
NSMutableArray *arrOrders = [[NSMutableArray alloc]init];
[arrOrders addObjectsFromArray:[[NSUserDefaults standardUserDefaults] objectForKey:#"Orders"]];
NSArray *filteredOrder = [arrOrders filteredArrayUsingPredicate:resultPredicate];
if ([filteredOrder count] > 0) {
NSUInteger index = [arrOrders indexOfObject:[filteredOrder objectAtIndex:0]];
if (index != NSNotFound) {
[arrOrders replaceObjectAtIndex:index withObject:OrderDetails];
}
}

You cannot replace an object with NSPredicate you can however search for it then do the replacement afterwards.
Well just made this up without testing but I do think it has a valid syntax.
You can use this as the foundation or hope you get the logic in using the predicate.
// construct the predicate with the given condition
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"order_id = %#",dictionary[#"order_id"]];
// this will filter the array according to the given predicate. if there are more than 1 entries with the given condition then you should handle that this only handle unique entries
NSArray *array = [orderList filteredArrayUsingPredicate:predicate];
// assuming that order_id is unique
NSInteger index = [orderList indexOfObject:[array lastObject]];
if (index != NSNotFound) // check if index is existing
[orderList replaceObjectAtIndex:index withObject:orderDetails]; // replace the object with the desired object

If I want to match perfect then I used, LIKE. Although I am not sure.
Got from the linkcheat sheet
NSPredicate *predicateSearchOrder=[NSPredicate predicateWithFormat:#"SELF.order_id LIKE[cd] %#",[responsedDict valueForKey:#"order_id"]];
//
// //It will be only one object with order id.
NSArray *searchedArray=[orderList filteredArrayUsingPredicate:predicateSearchOrder];
if(searchedArray.count>0){
NSDictionary *toModiFyDictionary=searchedArray[0];
toModiFyDictionary=OrderDetails;
}
This is also working

If you were using Swift, It's very simple.
public class Test : NSObject {
class func test() -> Void {
var array : [Dictionary<String, String>] = []
let dic: Dictionary<String, String> = ["order_id" : "111", "name" : "good1"]
let dic2: Dictionary<String, String> = ["order_id" : "222", "name" : "good2"]
let dic3: Dictionary<String, String> = ["order_id" : "111", "name" : "good3"]
array.append(dic)
array.append(dic2)
let result = array.map { (elem) -> [String : String] in
if elem["order_id"] == "111" {
return dic3
}
return elem
}
print("result = \(result)")
}
}

Related

ios How to filter two array using predicate on an object property [duplicate]

-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
[self.map removeAnnotations:self.map.annotations];
if ([textField isEqual:self.searchText]) {
NSPredicate *bPredicate =
[NSPredicate predicateWithFormat:#"name contains[c], %#",self.searchText.text];
self.filteredArray = [self.hotelArray filteredArrayUsingPredicate:bPredicate];
NSLog(#" HEARE %#",self.filteredArray);
[self markAllHotels];
}
return YES;
}
hotelArray and filteredArray are NSArrays.
hotelArray has objects of type hotel where hotel has a property name.
Problem :
I want to filter hotelArray according to hotel.name when hotel.name matches text entered in searchText [text field], but I am getting an empty self.filteredArray.
Try following lines, and make sure properyName is case sensitive. and you have placed , in predicate format, thats why its not working. just replace your code with following.
Objective C
NSPredicate *bPredicate = [NSPredicate predicateWithFormat:#"SELF.name contains[cd] %#",self.searchText.text];
self.filteredArray = [self.hotelArray filteredArrayUsingPredicate:bPredicate];
NSLog(#"HERE %#",self.filteredArray);
Swift
var bPredicate: NSPredicate = NSPredicate(format: "SELF.name contains[cd] %#", self.searchText.text)
self.filteredArray = self.hotelArray.filteredArrayUsingPredicate(bPredicate)
NSLog("HERE %#", self.filteredArray)
Using swift filter
var searchText = "Galaxy"
let filteredArray = hotelArray.filter { $0["name"] == searchText }
print("** Result ** \n\(filteredArray)")
Swift 3.0
let arrEmp = [["name": "James", "age" : 27, "city" : "New york"],
["name": "Johnson", "age" : 24, "city" : "London"],
["name": "Alex", "age" : 28, "city" : "Newark"],
["name": "Mark", "age" : 25, "city" : "Paris"],
["name": "Steve", "age" : 25, "city" : "Silicon Valley"],
["name": "Lary", "age" : 28, "city" : "New york"]]
// *** Filter by Name exact match ***
var filterByName = arrEmp.filter { $0["name"] == "Mark" }
print("filterByName \(filterByName)")
// *** Filter by Age ***
var filterByAge = arrEmp.filter { $0["age"] as! Int > 25 }
print("filterByAge \(filterByAge)")
Swift 4.0
var filterByName = arrEmp.filter
do {
$0["name"] == "Mark"
}
print("filterByName filterByName)")
var filterByAge = arrEmp.filter
do {
$0["age"] as! Int > 25
}
print("filterByAge filterByAge)")
Based on your information, this is your situation:
self.hotelArray // Array in which we perform a search
self.filteredArray // Result array
name // Property of the object used for the predicate
This predicate should work for you:
NSString *searchText = self.searchText.text;
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"self.name contains[c] %#", searchText];
self.filteredArray = [self.hotelArray filteredArrayUsingPredicate:predicate];
Checkout this library
https://github.com/BadChoice/Collection
It comes with lots of easy array functions to never write a loop again
So you can just do:
NSArray* hotels = [self.hotelArray filter:^BOOL(Hotel *hotel) {
[return hotel.name isEqualToString:searchText];
}];
or simply
NSArray* hotels = [self.hotelArray where:#"name" is:searchText];
:)
This is the predicate method that might work for you.
-(void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope
{
[filteredContactArray removeAllObjects];
NSArray *tempArray = [hotelArray filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"name contains[c] %# OR name contains[cd] %#",searchText]];
filteredArray = [NSMutableArray arrayWithArray:tempArray];//if you want the filtered array to be mutable or tempArray will work as as desired by you.
}
contains[c]- means the predicate with case sensitive.
contains[cd]- case insensitive string
I'm not sure if this is what you want to do :
-(NSArray*)searchString:(NSString*)stringToSearch inArray:(NSArray*)myArray
{
NSMutableArray* filtredArray = [[NSMutableArray alloc] init];
for (NSString* elmnt in myArray)
{
if ([elmnt rangeOfString:stringToSearch].location != NSNotFound) [fitredArray addObject:elmnt];
}
return filtredArray;
}

IOS Sort NSDictionary with given array order

I have a dictionary with objects and keys. I want to sort that dictionary using the keys
dict = [name : abc, city: xyz, date :xys, location: mnq ...]
for example i want to pass like
array = [name, location, city, date]
i want to sort the dicionary like
dict = [name : abc, location: mnq, city: xyz,date: xys ...]
It should sort dicationay,as per my passing array values
not like alphabet or allkeys or allValues order
NSArray *newkey = [[NSArray alloc] initWithObjects:#"name",#"location", #"city", #"date", nil];
int index = 0;
for (id key in dictionary) {
NSLog(#"key: %#, value: %#", [newkey objectAtIndex:index], [dictionary objectForKey:[newkey objectAtIndex:index]]);
index++;
}
u can't sort dictionary ... make 2D array with key - value pairs and sort them afterwards with .sort() function
var dict : NSMutableDictionary = NSMutableDictionary()
dict.setObject("damu", forKey: "name")
dict.setObject("bng", forKey: "city")
dict.setObject("sakha", forKey: "office")
dict.setObject("apple", forKey: "technology")
// Searching array
keysArray = ["name","city","office","tech"]
// returning Touple
var dictTouples = returnTouppleWithDictionary(dict, sortWithArray: keysArray)
print("\n\n Soreted as keys: \(dictTouples.allKeys) Values \(dictTouples.allValues) ")
// Touple
func returnTouppleWithDictionary(dict : NSDictionary, sortWithArray: NSArray) ->(allKeys:NSArray, allValues: NSArray){
var arrayKeys : NSMutableArray = NSMutableArray()
var arrayValues : NSMutableArray = NSMutableArray()
for i in 0..<keysArray.count{
var key : NSString = keysArray[i] as! String
var name: NSString? = dict.objectForKey(key) as! String;
arrayKeys.addObject(key)
arrayValues.addObject(name!)
}
return(arrayKeys,arrayValues)
}

Swift filter array using NSPredicate

I have an application written in Swift that is pulling in the users contacts from their address book.
I want to filter out the contact that only contain a company name (so that you get your "assumed" real person contact and not businesses)
Here is how this is being accomplish in the Objective-C version of my app:
NSArray *allContacts = (__bridge_transfer NSArray *)ABAddressBookCopyArrayOfAllPeople(addressBook);
NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(id person, NSDictionary *bindings) {
NSString *firstName = CFBridgingRelease(ABRecordCopyValue((__bridge ABRecordRef)person, kABPersonFirstNameProperty));
NSString *lastName = CFBridgingRelease(ABRecordCopyValue((__bridge ABRecordRef)person, kABPersonLastNameProperty));
return (firstName || lastName);
}];
NSArray *peopleNotCompanies = [allContacts filteredArrayUsingPredicate:predicate];
This works perfectly, so here is my attempt to do this in Swift:
var contactList: NSArray = ABAddressBookCopyArrayOfAllPeople(addressBook).takeRetainedValue()
var predicate: NSPredicate = NSPredicate { (AnyObject person, NSDictionary bindings) -> Bool in
var firstName: String = ABRecordCopyValue(person as ABRecordRef, kABPersonFirstNameProperty).takeRetainedValue() as String
var lastName: String = ABRecordCopyValue(person as ABRecordRef, kABPersonLastNameProperty).takeRetainedValue() as String
return firstName || lastName
})
Now this has a couple problems. I am getting these errors on the return statement and the end of the predicate call:
How can I provide similar functionality found in my ObjC code in Swift? Or is there a better way in swift to check if a contact has ONLY a company name and then omit it from the final array?
Thanks!
If you have firstName and lastName be optional strings, you can compare them against nil and use them in a boolean expression.
Your second error is due to the extra paren after your closure. This code should work.
var predicate: NSPredicate = NSPredicate { (AnyObject person, NSDictionary bindings) -> Bool in
var firstName: String? = ABRecordCopyValue(person as ABRecordRef, kABPersonFirstNameProperty).takeRetainedValue() as? String
var lastName: String? = ABRecordCopyValue(person as ABRecordRef, kABPersonLastNameProperty).takeRetainedValue() as? String
return firstName != nil || lastName != nil
}
If you convert the NSArray into a Swift Array, you can use Swift's Array.filter method. Here's an example with simpler objects for clarity:
let arrObjc: NSArray = ["aaa", "bab", "bbb", "baa", "cbc"]
let arr: [AnyObject] = arrObjc //create a swift array with same data
// filter takes a block that returns a boolean. True: keep the item, False: drop it.
arr.filter{
if let s = $0 as? String { // first try to cast AnyObject to our expected type.
return contains(s, "a") // return true if we want this item, false otherwise.
} else {
return false // this object is of the wrong type, return false.
}
}
// returns: ["aaa", "bab", "baa"]
Your test at the last line in Objective-C will return if firstName is nil or if lastName is nil. In your swift code, you are just trying to compare two strings as if they were Bools. Instead, you want to return if firstName exists, so you should instead do this in both your objective-c and Swift code:
return firstName != nil

iOS filter array of dictionary base on value and not the key

I have array with dictionaries like this:
Array: (
{
customerUS= {
DisplayName = "level";
InternalName = "Number 2";
NumberValue = 1;
},
customerCAN= {
DisplayName = "PurchaseAmount";
InternalName = "Number 1";
NumberValue = 3500;
};
}
)
I want to filter the dictionaries base on particular value and not the key. For example I want all the dictionaries with values on any key of 3500. Does any body knows how can I do this?
I'll really appreciate your help.
Try a predicate format like:
#"%# IN SELF", testValue
When you filter the array each will be run against the IN. When you pass IN a dictionary it uses the values of the dictionary.
you can also use
-keysOfEntriesPassingTest:
of NSDictionary. Just pass in a block like so:
for(NSDictionary *myDictionary in myArray){
NSSet *resultSet = [myDictionary keysOfEntriesPassingTest:^(id key, id object, BOOL *stop) {
//assuming that 3500 is an int, otherwise use appropriate condition.
if([[NSNumber numberWithInt:object] isEqual:[NSNumber numberWithInt:3500]]){
return YES;
}else{
return NO;
}
}];
if (resultSet.count>0){
//do whatever to myDictionary
}
}

Generate a complete list of key-value coding paths for nested NSDictionary's?

I have an NSDictionary that contains keys and values, and some values will also be NSDictionarys... to an arbitrary (but reasonable) level.
I would like to get a list of all valid KVC paths, e.g. given:
{
"foo" = "bar",
"qux" = {
"taco" = "delicious",
"burrito" = "also delicious",
}
}
I would get:
[
"foo",
"qux",
"qux.taco",
"qux.burrito"
]
Is there a simple way to do this that already exists?
You could recurse through allKeys. A key is a key path, obviously, and then if the value is an NSDictionary you can recurse and append.
- (void) obtainKeyPaths:(id)val intoArray:(NSMutableArray*)arr withString:(NSString*)s {
if ([val isKindOfClass:[NSDictionary class]]) {
for (id aKey in [val allKeys]) {
NSString* path =
(!s ? aKey : [NSString stringWithFormat:#"%#.%#", s, aKey]);
[arr addObject: path];
[self obtainKeyPaths: [val objectForKey:aKey]
intoArray: arr
withString: path];
}
}
}
And here is how to call it:
NSMutableArray* arr = [NSMutableArray array];
[self obtainKeyPaths:d intoArray:arr withString:nil];
Afterwards, arr contains your list of key paths.
Here is a Swift version I wrote after taking note from Matt's answer.
extension NSDictionary {
func allKeyPaths() -> Set<String> {
//Container for keypaths
var keyPaths = Set<String>()
//Recursive function
func allKeyPaths(forDictionary dict: NSDictionary, previousKeyPath path: String?) {
//Loop through the dictionary keys
for key in dict.allKeys {
//Define the new keyPath
guard let key = key as? String else { continue }
let keyPath = path != nil ? "\(path!).\(key)" : key
//Recurse if the value for the key is another dictionary
if let nextDict = dict[key] as? NSDictionary {
allKeyPaths(forDictionary: nextDict, previousKeyPath: keyPath)
continue
}
//End the recursion and append the keyPath
keyPaths.insert(keyPath)
}
}
allKeyPaths(forDictionary: self, previousKeyPath: nil)
return keyPaths
}
}

Resources