i want to convert an nsarray to nsdictionary i'm using to
- (NSDictionary *) indexKeyedDictionaryFromArray:(NSArray *)array
{
id objectInstance;
NSUInteger indexKey = 0;
NSMutableDictionary *mutableDictionary = [[NSMutableDictionary alloc] init];
for (objectInstance in array)
[mutableDictionary setObject:objectInstance forKey:[NSNumber numberWithUnsignedInt:indexKey++]];
return (NSDictionary *)[mutableDictionary autorelease];
}
output result is:
{
0 = {
Event = "";
ID = 1; };
3 = {
Event = "";
ID = 77; };
2 = {
Event = "";
ID = 23; };
1 = {
Event = "";
ID = 45; };
7 = {
Event = "";
ID = 10; };
5 = {
Event = "";
ID = 26; };
6 = {
Event = "";
ID = 27;
};
8 = {
Event = "";
ID = 28;
};
}
After convert to nsdictionary, the order of nsdictionary isn't true to the original order, i want to display the same order in nsarray, i don't know how? can you help me?
NSDictionary does not have an order. Sort the keys and use them to access the entries.
If I understand correctly from your responses to #ACB and #Zaph in the comments, you want to do the following:
Maintain a collection mapping integer keys to object values which is ordered by the keys.
If I'm understanding correctly, an array won't be good enough for your purposes because the integer keys in an array allow for no "holes". You, however, need to allow for holes: in the output in your question, the key-value pair for 4 is missing. For this reason, a dictionary is appealing to you.
Unfortunately, a dictionary will not allow you to maintain an ordering on the key-value pairs it contains, as #Zaph points out. You say, however, you just want to display the values in the dictionary ordered by the keys in a UITableView. Presumably, it is unimportant the order in which the dictionary is serialized to disk (using writeToFile:atomically:) so long as the contents of the dictionary are displayed in the correct order in the table view.
A dictionary can be used for this purpose as follows. First, we'll need a class PFXKeyValuePair;
#interface PFXKeyValuePair : NSObject
#property (nonatomic) id<NSCopying> key;
#property (nonatomic) id value;
+ (PFXKeyValuePair *)pairWithValue:(id)value forKey:(id<NSCopying>)key;
+ (NSArray *)pairsWithValues:(NSArray *)values forKeys:(NSArray *)keys;
#end
#implementation PFXKeyValuePair
+ (PFXKeyValuePair *)pairWithValue:(id)value forKey:(id<NSCopying>)key
{
PFXKeyValuePair *pair = [[PFXKeyValuePair alloc] init];
pair.value = value;
pair.key = key;
return pair;
}
+ (NSArray *)pairsWithValues:(NSArray *)values forKeys:(NSArray *)keys
{
NSAssert(values.count == keys.count, #"The array of values must be the same size as the array of keys.");
NSUInteger count = values.count;
NSMutableArray *mutableRes = [NSMutableArray array];
for (NSUInteger index = 0; index < count; index++) {
PFXKeyValuePair *pair = [PFXKeyValuePair pairWithValue:values[index] forKey:keys[index]];
[mutableRes addObject:pair];
}
return [mutableRes copy];
}
#end
Second, we'll need a category method on NSDictionary:
#interface NSDictionary (PFXAdditions)
- (NSArray *)pfx_keyValuePairsSortedByKeyUsingComparator:(NSComparator)comparator;
#end
#implementation NSDictionary (PFXAdditions)
- (NSArray *)pfx_keyValuePairsSortedByKeyUsingComparator:(NSComparator)comparator
{
NSArray *sortedKeys = [self.allKeys sortedArrayUsingComparator:comparator];
NSArray *sortedValues = [self objectsForKeys:sortedKeys notFoundMarker:[NSNull null]];
return [PFXKeyValuePair pairsWithValues:sortedValues forKeys:sortedKeys];
}
#end
Note: In the above, PFX and pfx are placeholders. You ought to replace them with prefixes appropriate to your project.
We can then use this category method when to populate our UITableView. Let's say we have a property
#property (nonatomic) NSDictionary *events;
And let's assume that the table view has only one section in which these events will be shown.
Then we can implement –tableView:numberOfRowsInSection: in our UITableViewController subclass as follows:
– (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.events.count;
}
And within our implementation of –tableView:numberOfRowsInSection: we can determine the appropriate entry in the dictionary to use as follows:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//...
NSArray *pairs = [self.events pfx_keyValuePairsSortedByKeyUsingComparator:^(id obj1, id obj2) {
NSNumber *key1 = (NSNumber *)obj1;
NSNumber *key2 = (NSNumber *)obj2;
return [key1 compare:key2];
}];
NSUInteger index = [indexPath indexAtPosition:1];
PFXKeyValuePair *pair = pairs[index];
/*
At this point, pair.value will be a dictionary as in your output above
holding a value for the key #"Event" and a value for the key #"ID".
*/
//...
}
This could be made faster by making pairs a property and only computing it when necessary (for example, by only computing pairs just prior to reloading the table's data).
Note: Using this approach, the dictionary will still not be serialized to disk (when calling -writeToDisk:atomically:) "in order" and your output will still look the same as in your question. However, this does not matter: when the data is displayed to the user in the table view, the data will be ordered as you're hoping.
This is example one of the exmple get the emplyee list NSMutableArray and create NSMutableDictionary.......
NSMutableArray *emloyees = [[NSMutableArray alloc]initWithObjects:#"saman",#"Ruchira",#"Rukshan",#"ishan",#"Harsha",#"Ghihan",#"Lakmali",#"Dasuni", nil];
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
for (NSString *word in emloyees) {
NSString *firstLetter = [[word substringToIndex:1] uppercaseString];
letterList = [dict objectForKey:firstLetter];
if (!letterList) {
letterList = [NSMutableArray array];
[dict setObject:letterList forKey:firstLetter];
}
[letterList addObject:word];}NSLog(#"dic %#",dict);
Related
There is an array having same objects in single array , i need to compare these array’s index with another array.. Give me a help.
Something like:
NSMutableArray *latArray =
[NSMutableArray arrayWithObjects:#“43.20,#“43.23”,#“43.24”,#“43.20”,nil];
NSMutableArray *lngArray =
[NSMutableArray arrayWithObjects:#“76.90”,#“76.94”,#“76.92”,#“76.90”,nil];
NSMutableArray *imagesArray =
[[NSMutableArray alloc] initWithObjects:#"1.jpg", #"2.jpg”,#“3.jpg”,#“4.jpg”,nil];
resultResult = #"1.jpg", #“4.jpg” // because the index 0 and index 3 same values in both array.
I would wrap your coordinates into location objects and use them as the keys in a dictionary. This would allow to check for duplicate coordinates, like this:
NSMutableDictionary *results = [[NSMutableDictionary alloc] init];
for (int i = 0; i < [imagesArray count]; i++)
{
// Wrap coordinates into a NSValue object
// (CLLocationCoordinate2D is a C-struct that cannot be used as a dictionary key)
// (CLLocation also does not implement required methods to be usable as a dictionary key)
NSValue *loc = [NSValue valueWithMKCoordinate:CLLocationCoordinate2DMake(
((NSNumber)[latArray objectAtIndex:i]).doubleValue,
((double)[lngArray objectAtIndex:i]).doubleValue)];
// 1. If you only want the first occurrence of a specific location, use this:
if ([results objectForKey:loc] == nil)
{
[results setObject:[imagesArray objectAtIndex:i] forKey:loc];
}
// 2. Or, if you want the last occurrence of a specific location, use this:
[results setObject:[imagesArray objectAtIndex:i] forKey:loc];
}
I think you are trying the check for the same objects in an array. If so do the following.
for(int i=0;i<yourarray.count;i++)
{
NSString *yourstring=[yourarray objectatindex:i];
for(int k=0;k<yourarray.count;k++)
{
if(i!=k)
{
NSString *yourstring2=[yourarray objectatindex:k];
if([yourstring isEqualtostring yourstring2])
{
//now you got equal objects. do what ever you want here
}
}
}
}
i have a Array of Dict , which display a Specific data into tableview ,I've been reading up on how to sort arrays of objects using the value of a property, and how to sort an array of NSDictionaries using one of their keys,
My Question is :-
how to customize header of Section in TableView and using category as a header section , see the screenshot i want to do the same thing .
(
{
categories = Protection;
"name_en" = "Wind deflectors, front";
"part_number" = A4221ADE00;
"part_pic1" = "a4221ade00/a4221ade00.jpg";
},
{
categories = Protection;
"name_en" = "Ice & sunscreen";
"part_number" = A4723ADE00;
"part_pic1" = "a4723ade00/a4723ade00.jpg";
},
{
categories = Protection;
"name_en" = "Carens-UN-BK-2009-AccBrochure";
"part_number" = "Carens-UN-BK-2009-AccBrochure";
"part_pic1" = "carens-un-bk-2009-accbrochure/carens-un-2009.jpg";
},
{
categories = Transport;
"name_en" = "Battery Petrol engines 2.0 GDI / Diesel engine 1.7 CRDi Carens";
"part_number" = LP370APE070CK0;
"part_pic1" = "b2143ade00ev/b2143ade00ev-soul2014-ev-floormat.jpg";
})
Not sure I entirely understand the question, but I'll take a stab. So the first step sounds like you want to sort the array of dictionaries based on the #"categories" key. This will put the array in alphabetical order based on that key:
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:#"categories" ascending:YES];
NSArray *sortedArray = [arrayOfDictionaries sortedArrayUsingDescriptors:#[sortDescriptor]];
Then you want the section headers of the table to be the names of the categories. First you will need to find out how many different categories there are. A method like this can get that into an array without duplicates:
+ (NSArray *)findCategoriesInArray:(NSArray *)arrayOfDictionaries
{
NSMutableArray *categories = [NSMutableArray array];
for (id object in arrayOfDictionaries) {
if ([object isKindOfClass:[NSDictionary class]]) {
NSDictionary *dictionary = (NSDictionary *)object;
if (dictionary[#"categories"] && ![categories containsObject:dictionary[#"categories"]]) {
[categories addObject:dictionary[#"categories"]];
}
}
}
return categories;
}
At this point you have an array of all the dictionaries sorted by the categories key and an array containing the different categories. Let's assume the categories array from the method above gets assigned to a property self.categories (which is an NSArray). So now we can populate the section headers in the normal method calls:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return self.categories.count;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
return (NSString *)self.categories[section]; // I'm assuming these are all strings
}
Finally, we can populate the rows in each section:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSString *headerTitle = (NSString *)self.categories[section];
return [NameOfClass findNumberOfCategory:headerTitle inArray:self.arrayOfDictionaries];
}
+ (NSInteger)findNumberOfCategory:(NSString *)category inArray:(NSArray *)arrayOfDictionaries
{
NSInteger number = 0;
for (id object in arrayOfDictionaries) {
if ([object isKindOfClass:[NSDictionary class]]) {
NSDictionary *dictionary = (NSDictionary *)object;
if (dictionary[#"categories"] && [dictionary[#"categories"] isKindOfClass:[NSString class]]) {
NSString *thisCategory = (NSString *)dictionary[#"categories"];
if ([thisCategory isEqualToString:category]) {
number++;
}
}
}
}
return number;
}
Assuming both the self.arrayOfDictionaries and the self.categories arrays are both in alphabetical order, you can populate the cells themselves in tableView:cellForRowAtIndexPath: by getting the properties of the object from self.arrayOfDictionaries[indexPath.row].
How to add and get the values from NSDictionary without key sorting?
NSDictionary is sorting the keys automatically.
How to get dictionary on added object format without sorting?
I have added the objects in below order.
NSDictionary *ScroesDic = [NSDictionary dictionaryWithObjectsAndKeys:#3,#"id_player",#100,#"shots[0][power]",#90,#"shots[0][precision]",#72,#"shots[1][power]",#27,#"shots[1][precision]",#23,#"shots[2][power]",#80,#"shots[2][precision]",#23,#"shots[3][power]",#80,#"shots[3][precision]",#23,#"shots[4][power]",#80,#"shots[4][precision]",#23,#"shots[5][power]",#80,#"shots[5][precision]",#23,#"shots[6][power]",#80,#"shots[6][precision]",#23,#"shots[7][power]",#80,#"shots[7][precision]",#23,#"shots[8][power]",#80,#"shots[8][precision]",#23,#"shots[9][power]",#80,#"shots[9][precision]",#23,#"shots[10][power]",#80,#"shots[10][precision]",#23,#"shots[11][power]",#80,#"shots[11][precision]",#23,#"shots[12][power]",#80,#"shots[12][precision]", nil];
NSLog(#"%#",ScroesDic);
But,the dictionary returns below order.
{
"id_player" = 3;
"shots[0][power]" = 100;
"shots[0][precision]" = 90;
"shots[10][power]" = 23;
"shots[10][precision]" = 80;
"shots[11][power]" = 23;
"shots[11][precision]" = 80;
"shots[12][power]" = 23;
"shots[12][precision]" = 80;
"shots[1][power]" = 72;
"shots[1][precision]" = 27;
"shots[2][power]" = 23;
"shots[2][precision]" = 80;
"shots[3][power]" = 23;
"shots[3][precision]" = 80;
"shots[4][power]" = 23;
"shots[4][precision]" = 80;
"shots[5][power]" = 23;
"shots[5][precision]" = 80;
"shots[6][power]" = 23;
"shots[6][precision]" = 80;
"shots[7][power]" = 23;
"shots[7][precision]" = 80;
"shots[8][power]" = 23;
"shots[8][precision]" = 80;
"shots[9][power]" = 23;
"shots[9][precision]" = 80;
}
NSDictionary is not meant to be sorted. You can get it sorted by getting all keys using allKeys and sorting that array to your liking. Then loop through this array and get the corresponding values.
Here is one way of doing it:
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:#"key" ascending:YES comparator:^(id obj1, id obj2) {
if (obj1 > obj2) {
return (NSComparisonResult)NSOrderedDescending;
}
if (obj1 < obj2) {
return (NSComparisonResult)NSOrderedAscending;
}
return (NSComparisonResult)NSOrderedSame;
}];
NSArray *sortedKeys = [[filteredDictionary allKeys] sortedArrayUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];
NSMutableDictionary *orderedDictionary = [NSMutableDictionary dictionary];
for (NSString *index in sortedKeys) {
[orderedDictionary setObject:[filteredDictionary objectForKey:index] forKey:index];
}
filteredDictionary = orderedDictionary;
May it helps you.
Like an NSSet, the NSDictionary class represents an unordered
collection of objects; however, they associate each value with a key,
which acts like a label for the value.
You dont need to order the NSDictionary in anyway.That's make no sense. Because you are accessing the object by using the key not in any order.
By documentation, keys order in a NSDictionary is not defined:
allKeys
Returns a new array containing the dictionary’s keys.
(NSArray *)allKeys
Return Value
A new array containing the dictionary’s keys, or an empty array if the dictionary has no > entries.
Discussion
The order of the elements in the array is not defined.
If you want to keep a particular order of your keys, let's say the "insertion order" what you can do is subclass NSDictionary (difficult, as you should maintain the complex internal API coherent) or make a new class which contains internally a NSDictionary + NSArray to keep the insertion order of the keys, and then build a custom API similar to the NSDictionary one (but just a small subset of the methods you really need). E.g. of a mutable class:
#interface MyDictionary ()
#property (strong,nonatomic) NSMutableDictionary *internalDictionary;
#property (strong,nonatomic) NSMutableArray *internalArray;
#end
#implementation MyDictionary
-(id)init {
self = [super init];
if(self) {
_internalDictionary = [NSMutableDictionary new];
_internalArray = [NSMutableArray new];
}
}
-(void)setObject:(id)value forKey:(id)key {
_internalDictionary[key]=value;
// add key in array only if not already added yet
if(![_internalArray containsObject:key]) {
[_internalArray addObject:key];
}
}
#end
Hi I have an instance variable NSMutable Array.
I declare it as such
#property (nonatomic, assign) NSMutableArray *list;
In viewDidLoad I instantiate it.
self.list = [NSMutableArray array];
I then make a string consisting of the text of text fields and add it to the array.
NSString * lines = [NSString stringWithFormat:#"%#,%#,%#,%#,%#", [self.crabText text], [self.trawlText text], [self.trapText text], [self.vesselText text], [self.lengthText text]];
[self.list addObject:lines];
This is apart of a function which will keep on adding new values of the text fields into the array.
I display the contents of the array with
int i;
int count;
for (i = 0, count = [self.list count]; i < count; i = i + 1)
{
NSString *element = [self.list objectAtIndex:i];
NSLog(#"The element at index %d in the array is: %#", i, element); // just replace the %# by %d
}
However, the app crashes when I try to print the contents of the array and I get
EXC_BAD_ACCESS_CODE
Any ideas?
Thanks!
Replace your declaration like this :
#property (nonatomic, strong) NSMutableArray *list; // strong and not assign
Initialize your array in your viewDidLoad :
self.list = [NSMutableArray array];
and add one by one your string :
[self.list addObject:self.crabText.text];
[self.list addObject:self.trawlText.text];
....
Next, modify your for loop :
for (int i = 0, i < self.list.count, i++)
{
NSLog(#"The element at index %d in the array is: %#", i, [self.list objectAtIndex:i]);
}
Another way to do this would be to declare the array this way in your header file
#interface yourViewController : UIViewController
{
NSMutableArray* list;
}
#end
Then in the ViewDidLoad
list = [[NSMutableArray alloc] init];
Everything else can be done just as Jordan said. Though I'm not sure if there is a difference in performance between either implementation.
We have an app that calls a SOAP web service and retrieves a long list of XML, which the app then parses into an NSArray of NSDictionary objects. The NSArray contains a list of Rental Apartment information, each of which is stored into an NSDictionary.
The entire list may contain 10 different types of Apartments (i.e. 2-room, 3-room), and we need to split the NSArray into smaller NSArrays based on Room-Type, which has the key "roomType" in the NSDictionary objects.
Currently our algorithm is
Use [NSArray valueForKeyPath:#"#distinctUnionofObjects.room-type"]
to obtain a list of unique room-type values.
Loop through the list of unique room-type values
For each unique room-type value, use NSPredicate to retrieve matching items from the Original list
Our code is below (renamed for clarity):
NSArray *arrOriginal = ... ...; // Contains the Parsed XML list
NSMutableArray *marrApartmentsByRoomType = [NSMutableArray arrayWithCapacity:10];
NSMutableArray *arrRoomTypes = [arrOriginal valueForKeyPath:#"distinctUnionOfObjects.roomType"];
for(NSString *strRoomType in arrRoomTypes) {
NSPredicate *predicateRoomType = [NSPredicate predicateWithFormat:#"roomType=%#", strRoomType];
NSArray *arrApartmentsThatMatchRoomType = [arrOriginal filteredArrayUsingPredicate:predicateRoomType]; // TAKES A LONG TIME EACH LOOP-ROUND
[marrApartmentsByRoomType addObject:arrApartmentsThatMatchRoomType];
}
However, step 3 is taking a long time as the original list may contain large amount (>100,000) of items. It seems that NSPredicate goes through the entire list for each key value. Is there a more efficient way of splitting a large NSArray into smaller NSArrays, based on NSDictionary keys?
If the order of your splited Arrays is not important, i have a solution for you:
NSArray *arrOriginal;
NSMutableDictionary *grouped = [[NSMutableDictionary alloc] initWithCapacity:arrOriginal.count];
for (NSDictionary *dict in arrOriginal) {
id key = [dict valueForKey:#"roomType"];
NSMutableArray *tmp = [grouped objectForKey:key];
if (tmp == nil) {
tmp = [[NSMutableArray alloc] init];
[grouped setObject:tmp forKey:key];
}
[tmp addObject:dict];
}
NSMutableArray *marrApartmentsByRoomType = [grouped allValues];
This is quite performant
- (NSDictionary *)groupObjectsInArray:(NSArray *)array byKey:(id <NSCopying> (^)(id item))keyForItemBlock
{
NSMutableDictionary *groupedItems = [NSMutableDictionary new];
for (id item in array) {
id <NSCopying> key = keyForItemBlock(item);
NSParameterAssert(key);
NSMutableArray *arrayForKey = groupedItems[key];
if (arrayForKey == nil) {
arrayForKey = [NSMutableArray new];
groupedItems[key] = arrayForKey;
}
[arrayForKey addObject:item];
}
return groupedItems;
}
Improving #Jonathan answer
Converting array to dictionary
Maintaining the same order as it was in original array
//only to a take unique keys. (key order should be maintained)
NSMutableArray *aMutableArray = [[NSMutableArray alloc]init];
NSMutableDictionary *dictFromArray = [NSMutableDictionary dictionary];
for (NSDictionary *eachDict in arrOriginal) {
//Collecting all unique key in order of initial array
NSString *eachKey = [eachDict objectForKey:#"roomType"];
if (![aMutableArray containsObject:eachKey]) {
[aMutableArray addObject:eachKey];
}
NSMutableArray *tmp = [grouped objectForKey:key];
tmp = [dictFromArray objectForKey:eachKey];
if (!tmp) {
tmp = [NSMutableArray array];
[dictFromArray setObject:tmp forKey:eachKey];
}
[tmp addObject:eachDict];
}
//NSLog(#"dictFromArray %#",dictFromArray);
//NSLog(#"Unique Keys :: %#",aMutableArray);
//Converting from dictionary to array again...
self.finalArray = [[NSMutableArray alloc]init];
for (NSString *uniqueKey in aMutableArray) {
NSDictionary *aUniqueKeyDict = #{#"groupKey":uniqueKey,#"featureValues":[dictFromArray objectForKey:uniqueKey]};
[self.finalArray addObject:aUniqueKeyDict];
}
Hope, It will help when client wants final array in same order as input array.