Reputation: 23
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
Upvotes: 1
Views: 671
Reputation: 266
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.
Upvotes: 2