IOS Sort NSDictionary with given array order - ios

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)
}

Related

Array to nested Dictionary in iOS?

There are a lot of questions with similar title but no one answers my question.
In my case I have an array:
["1", "2", "3", "4"]
And resulting dictionary should be:
["1": ["2": ["3": "4"]]]
How to convert it correctly? As I understand map, reduce and the similar functions doesn't have such functionality. And is it possible to do without of writing a recursive method?
Both Objective-C and Swift are applicable
A Swift solution, using reduce:
let a = ["1", "2", "3", "4"]
let d = a.dropLast(2).reversed()
.reduce([a[a.count - 2] : a[a.count - 1]]) { [$1 : $0] }
print(d) // ["1": ["2": ["3": "4"]]]
Here it is assumed that the array has at least 2 elements.
In our example, ["3", "4"] is the initial value for reduce,
and for the remaining elements in reverse order, a nested dictionary
is created in the closure with [$1 : $0].
The type of the result is [String: Any], which bridges to
NSDictionary if necessary.
//Your array
NSArray *a = #[#1,#2,#3,#4];
//Get the two last values (considering your array length must be at least 2 !
NSDictionary *last = #{a[a.count-2]:a[a.count-1]};
//In reverse order we assign last created dictionary to the current key, the array length must be superior than 3
for (NSInteger i = a.count - 3; i >= 0; i--)
last = #{a[i]:last};
NSLog(#"My dictionary %#", last);
Recursive option.
func toNestedDictionary(arr: [String]) -> [String: Any?]? {
if arr.isEmpty {
return nil
}
else if arr.count == 1 {
return Dictionary(dictionaryLiteral: (arr.first!, nil))
}
else if arr.count == 2 {
return Dictionary(dictionaryLiteral: (arr.first!, arr.last!))
}
else {
let head = arr.first!
let tail = arr.dropFirst()
return Dictionary(dictionaryLiteral: (head, toNestedDictionary(arr: Array(tail))))
}
}
print (toNestedDictionary(arr: ["1"]))
// Optional(["1": nil])
print (toNestedDictionary(arr: ["1", "2"]))
// Optional(["1": Optional("2")])
print (toNestedDictionary(arr: ["1", "2", "3"]))
// Optional(["1": Optional(["2": Optional("3")])])
print (toNestedDictionary(arr: ["1", "2", "3", "4"]))
// Optional(["1": Optional(["2": Optional(["3": Optional("4")])])])
Try below lines without recursion
NSArray *arr = #[#"1", #"2", #"3", #"4"];
NSMutableDictionary *dic = [[NSMutableDictionary alloc] init];
for (int i = arr.count-2; i>=0;i--) {
if (i == arr.count-2) {
[dic setObject:arr[i+1] forKey:arr[i]];
} else {
NSDictionary *tempDic = dic;
dic = #{arr[i]:tempDic};
}
}
NSLog(#"Solution%#",dic);
This problem can be solved using recursive programming easily. Here is the solution using Swift;
var ary = ["1", "2", "3", "4"]
func recursive(array:[String]) -> Any {
if ary.count > 1 {
let key = ary.removeFirst()
return [key : recursive(array: array)]
} else {
return array.last!
}
}
let reuslt = recursive(array: ary)
And result is: ["1": ["2": ["3": "4"]]]
Given a list
var list = ["1", "2", "3", "4"]
you can write
if let lastValue = list.popLast(), let lastKey = list.popLast() {
let dict = list.reversed().reduce([lastKey:lastValue]) { [$1:$0] }
print(dict)
}
Result
["1": ["2": ["3": "4"]]]
Please note that this code only works if the list contains at least 2 elements
Found a simplier solution:
NSMutableArray *tempArr = [array mutableCopy];
while (tempArray.count > 1) {
id value = tempArr.lastObject;
[tempArr removeLastObject];
NSString *key = tempArr.lastObject;
[tempArr removeLastObject];
[tempArr addObject:#{key: value}];
}
id result = tempArr.firstObject;

Replace an Dictionary object in Array using NSPredicate

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)")
}
}

Array with array inside

I need to create an array with personal name inside,and on this name,another array with personal information.Basically an array with another array inside divided by name.
Es:Array[luca [born:x age:y lives:z] marco[born:x age:y lives:z]......}
How can i do that?
Very simple, use modern Objective-C literals.
NSDictionary *luca = #{#"name" : #"luca",
#"born" : #(1997),
#"lives" : #(5)};
NSDictionary *marc = #{#"name" : #"marc",
#"born" : #(1998),
#"lives" : #(2)};
NSArray *people = #[luca, marc];
Your brief description indicates that you might want a dictionary of dictionaries. However, what you want here is an array of dictionaries or an array of objects.
var people = [ ["name": "Luca", "born": x, "age": y, "lives": z],
... ]
or
struct Person {
var name:String
var born:Int16
var age:Int16
var lives:Int16
}
var array = [Person(name: "Luca", born: x, age: y, lives: z),
...]
To add onto these answers you can also easily create a mutable NSMutableDictionary or NSMutableArray using literal syntax as follows:
NSMutableDictionary *dict = [#{#"asdf":#"asdf"} mutableCopy];
NSMutableArray *arr = [#[#"asdf"] mutableCopy];

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

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