Removing Objects from NSMutableDictionary - ios

I have a NSDictionary named tableData that contains keys #"A" - #"Z" and for every key the value contains an array with Patient objects.
I then create a NSMutableDictionary named filteredPatients and initialize it with the tableData dictionary.
In this example I try to remove all the Patient objects from the array where the key is #"A"
#property (nonatomic, strong) NSDictionary *tableData;
#property (nonatomic, strong) NSMutableDictionary *filteredPatients;
self.filteredPatients = [[NSMutableDictionary alloc]initWithDictionary:self.tableData];
NSMutableArray *patientArray = [self.filteredPatients objectForKey:#"A"];
int count = patientArray.count - 1;
for (int i = count; i >= 0; i--)
{
[patientArray removeObjectAtIndex:i];
}
In this case, the Patient Objects are getting removed correctly from filteredPatients array with key #"A", but the problem lay in the fact that the same Patient Objects are getting removed from tableData array with key #"A". My question is why are the Patient Objects being removed from the tableData dictionary as well? How do I prevent this?
I must be doing something wrong, but this puzzles me because if I try to simply remove the the key #"A" from filteredPatients, it works perfectly fine and only removes the key from the dictionary I want.
[self.filteredPatients removeObjectForKey:#"A"];

I think your problem is you're expecting deep copy behaviour but you haven't asked for a deep copy. The dictionaries are different objects, but the value for any given key in both dictionaries points to the same mutable array. You could use initWithDictionary:self.tableData copyItems:YES instead, but you're going to need to think through what gets copied and what doesn't. I don't have enough information to help you with that.

Related

Why do empty objects appear in OC array?

When I assign one array to another, I get an error, as shown in P1.
Then I checked the contents of _carIDArray and found an empty object in it. It was this object that caused the crash.P2
Why do empty objects appear in arrays? When using addobjcet: will not the array crash?
Here's some codes related to _carIDArray:
CarModel *car = [[CarModel alloc] initWithStatusAndMsgWithDic:object];
if (!_carIdArray) {
_carIdArray = [NSMutableArray array];
}
if (car.carIdStr && car.carIdStr.length>0){
[_carIdArray addObject:car.carIdStr];
}
*object is the data from the server.
#interface CarModel : NSObject
#property (nonatomic,copy) NSString *carIdStr;
#end

How to sort NSArray items into groups based on the same object order in a different NSArray? [duplicate]

This question already has answers here:
Sort NSArray of custom objects based on sorting of another NSArray of strings
(5 answers)
Closed 7 years ago.
I have an NSArray of unique UUIDs sorted in the proper order. I also have another NSArray of bookmarks with a UUID encoding. I would like to sort my NSArray of bookmarks based on their UUID property into groups.
For example, I have an NSArray: #[#"uuid1", #"uuid3", #"uuid2"] that has been sorted into this particular order. Now the other NSArray must sort all of its bookmarks in the same order as the first NSArray above.
So the second NSArray is: #[#"bookmark1", #"bookmark2", #"bookmark3", ...etc.]
Say bookmark 1 has the UUID property encoded as uuid2, bookmark 2 has the UUID encoding of uuid 1, but the bookmark 3 has encoding of uuid3. How can I sort and group these bookmarks so that it would be: #[#"bookmark2", #"bookmark3", #"bookmark1"]?
Thanks!
You could get rid of the second array and use a dictionary instead, which is keyed on the UUID.
NSArray *sortedIDs = #[ #"uuid1", #"uuid3", #"uuid2", ];
NSDictionary *items = #{
#"uuid1" : #[ bookmark1 ],
#"uuid2" : #[ bookmark2 ],
#"uuid3" : #[ bookmark3 ],
};
Now when you want the second bookmark you can access it with
NSArray *bookmarksForUUID = items[sortedIDs[1]];
If you wanted to build the structure above you could add a category like the below to NSArray
- (NSDictionary *)pas_groupBy:(id (^)(id object))block;
{
NSParameterAssert(block);
NSMutableDictionary *groupedDictionary = NSMutableDictionary.new;
for (id object in self) {
id key = block(object);
if (groupedDictionary[key]) {
[groupedDictionary[key] addObject:object];
} else {
groupedDictionary[key] = [NSMutableArray arrayWithObject:object];
}
}
return groupedDictionary;
}
Then assuming your bookmark objects look something like
#interface Bookmark : NSObject
#property (nonatomic, copy) NSString *UUID;
// other properties
// other properties
#end
You can use the category like this
NSDictionary *bookmarksMappedBySection = ({
return [bookmarks pas_groupBy:^(Bookmark *bookmark) {
return bookmark.UUID;
};
});
Create a class Bookmark. Add both the UUIDs and title as properties to this class. Now you can have just one array which holds objects of class Bookmark and each one will have access to its UUID and title (as well as any other properties you might want to add later on).
#interface Bookmark: NSObject
#property (nonatomic,strong) NSString *uuid;
#property (nonatomic,strong) NSString *title;
#end
Now if you have NSArray (lets call it myBookmarks) you can do the following:
for (Bookmark *bookmark in myBookmarks) {
NSLog(#"my UUID is %#",bookmark.uuid);
NSLog(#"my title is %#",bookmark.title);
}
If you need to store these items in NSUserDefaults all you have to do is adopt the NSCoding protocol. If you don't know how to do it here is a great and simple example.

Breaking NSArray into sorted groups by key

Noob here, could use some help.
I have an NSArray filled with MPMediaItems (songs) that I need to shuffle, by album. What I ultimately need to do:
1) Group tracks by album (total number of albums unknown).
2) Sort tracks within album by their track number.
3) Return a new array with all tracks (randomized by group, and still in order by number within their group).
I believe I know how I can do this by iterating through the array over and over, but this seems terribly inefficient. I suspect that an NSDictionary might be a better choice, but I don't even know where to begin.
Any help would be most appreciated!
Mike
Even though I haven't worked with MPMediaItems, I can explain how simple sorting and filtering can be for NSArray.
For the purpose of illustration I am creating an imaginary class called Song which may not be similar to MPMediaItem. Song class has two properties called albumName and trackNumber. Then we add a class method called + (NSDictionary *)songsGroupedByAlbumAndSortedByTrack:(NSArray *)songs that will accept an array of Song objects and returns an NSDictionary. Each key in the returned dictionary will be an albumName and the corresponding value will be an array of songs belonging to that album and sorted by track number.
#interface Song : NSObject
#property (nonatomic, copy) NSString *albumName;
#property (nonatomic, assign) NSInteger trackNumber;
#end
#implementation Song
+ (NSDictionary *)songsGroupedByAlbumAndSortedByTrack:(NSArray *)songs {
NSSortDescriptor *byTrack = [NSSortDescriptor sortDescriptorWithKey:#"trackNumber" ascending:YES];
NSArray *albumNames = [songs valueForKeyPath:#"#distinctUnionOfObjects.albumName"];
NSMutableDictionary *groupedByAlbumAndSortedByTrack = [[NSMutableDictionary alloc] init];
for (NSString *album in albumNames) {
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"albumName == %#",album];
NSArray *currentAlbumSongs = [songs filteredArrayUsingPredicate:predicate];
NSArray *currentAlbumSongsSortedByTrack = [currentAlbumSongs sortedArrayUsingDescriptors:#[byTrack]];
[groupedByAlbumAndSortedByTrack setObject:currentAlbumSongsSortedByTrack forKey:album];
}
return groupedByAlbumAndSortedByTrack;
}
#end
By using the NSSortDescriptor for sorting and NSPredicate for filtering we have eliminated a lot of looping through the array.
First step is to extract the album names from the array of songs which we accomplish using the KVC collectionOperator #distinctUnionOfObjects.
Then we iterate through the array of album names and add all songs belonging to that album to an NSArray.
The sample code given above is for sorting and filtering of NSArray in general.
A quick glance at the MPMediaItem class reference shows that apple already provides a lot of methods for manipulation of mediaItems. Please have a look at MPMediaPropertyPredicate.

Keep NSArray original order in NSCountedSet

I have an NSArray and I need to get data from two keys and put together in a NSMutableDictionary. One key has stringvalues and the other NSNumbervalues. When I try to create NSCountedSetwithout adding the keys I want to use to separate arrays, it doesn't work, because the objects are not identical, basically, I need to check if objectId is identical, don't matter if the other keys are different.
Here is the initial code:
for (PFObject *objeto in objects) {
PFObject *exercicio = objeto[#"exercicio"];
NSString *string = exercicio.objectId;
NSNumber *nota = objeto[#"nota"];
[exercicios addObject:string];
[notas addObject:nota];
So I create two NSMutableArraysand store the values I need. When I logthe arrays after this, they are perfectly ordered, meaning the NSStringis in the same indexof the NSNumberit belongs to in the other array. So far, so good.
Now, when I create the NSCountedSetwith the strings, it changes the order.
NSCountedSet *countedExercicios = [[NSCountedSet alloc] initWithArray:exercicios];.
My goal is to sum the NSNumbers pertaining to an specific object, therefore, when the order changes, I lose the connection between the two arrays.
I'm not sure what I could do to solve this problem, or even if there's a different approach to achieve the result I need.
You can create NSDictionary and add it to array. You will have just one array and you won't lose the connection, you can use objectId as a key and NSNumber as a value:
for (PFObject *objeto in objects) {
PFObject *exercicio = objeto[#"exercicio"];
NSString *string = exercicio.objectId;
NSNumber *nota = objeto[#"nota"];
NSDictionary *dict = #{string: nota};
[newArray addObject: dict];
}
When you need get all key (objectId) you can use NSPredictate.
Hope this help

adding array in NSDictionary and ordering it [duplicate]

This question already has answers here:
how to change order of NSMutable array in same way another mutable arrays get changed
(5 answers)
Closed 9 years ago.
i have three array like below
names birthdate remanning
"Abhi Shah", "01/14", 300
"Akash Parikh", "12/09/1989", 264
"Anand Kapadiya", "12/01", 256
"Annabella Faith Perez", "03/02", 347
"Aysu Can", "04/14/1992", 25
"Chirag Pandya" "10/07/1987" 201
plz it will be great help if you give me code for how to add this three array in NSDictionary and then after ordering(ascending) whole dictionary in accordance to "remaning" array
Note in Dic everything should get changed. not only remaning array. names and birthdate should get changed in same way remaning days are getting changed
thank you so much in advance
I would advise you to change the design of your project and create a model for same as having properties :
#interface YourModel : NSObject
#property (strong) NSString *name;
#property (strong) NDDate *birthDate;
#property NSInteger remaining;
#end
And then create an NSMutableArray in your class, and go on to add them.
This will make your work easier, as searching, sorting, filtering , than handling 3 parallel arrays.
You have to take each record (names, birthdate, remanning ) in the dictionary or any structure. And array of that dictionary should be created. To sort the array as per your requirement any sorting mechanism can be used.
-(void)sort
{
//This is the array of dictionaries, where each dictionary holds a record
NSMutableArray * array;
//allocate the memory to the mutable array and add the records to the arrat
// I have used simple bubble sort you can use any other algorithm that suites you
//bubble sort
//
for(int i = 0; i < [array count]; i++)
{
for(int j = i+1; j < [array count]; j++)
{
NSDictionary *recordOne = [array objectAtIndex:i];
NSDictionary *recordTwo = [array objectAtIndex:j];
if([[recordOne valueForKey:#"remaining"] integerValue] > [[recordTwo valueForKey:#"remaining"] integerValue])
{
[array xchangeObjectAtIndex:i withObjectAtIndex:j];
}
}
}
//Here you get the sorted array
}
Hope this helps.
If you use the design proposed by Anoop, the sorting code using blocks would be something similar to this:
NSArray *sortedArray = [yourArray sortedArrayUsingComparator:^NSComparisonResult(id a, id b) {
NSInteger first = [(YourModel*)a remaining];
NSInteger second = [(YourModel*)b remaining];
return [first compare:second];
}];

Resources