Reputation: 198
As it stands, the following code pulls data from the array "cellArray" to form an UICollectionView with 25 cells. I want to randomize the data being used without repeat. As of right now, there is only 25 array elements. Later on, there will be more, but I only want 25 cells to appear. I tried inserting "NSUInteger randomIndex = arc4random() % [theArray count];" However, I couldn't get it to work, and from my understanding, this has modulo bias.
It would also be a bonus if the 13th cell could have constant(non changing) text.
@implementation CollectionViewController
//Delegate Methods
-(NSInteger) numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return 1;
}
-(NSInteger) collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return self.cellArray.count;
}
-(UICollectionViewCell*) collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
Cell * aCell = [collectionView dequeueReusableCellWithReuseIdentifier:@"bingoCell1" forIndexPath:indexPath];
aCell.cellContent.text = self.cellArray[indexPath.row];
return aCell;
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
self.cellArray =
@[@"Type 1", @"Type 2", @"Type 3", @"Type 4", @"Type 5", @"Type 6", @"Type 7", @"Type 8", @"Type 9", @"Type 10", @"Type 11", @"Type 12", @"Free Space", @"Type 14", @"Type 15", @"Type 16", @"Type 17", @"Type 18", @"Type 19", @"Type 20", @"Type 21", @"Type 22", @"Type 23", @"Type 24", @"Type 25"];
}
Upvotes: 3
Views: 498
Reputation: 11595
Perform an in-place shuffle on self.cellArray
to randomize its order without repeats. I took the shuffling code from this question, which should be placed in an NSMutableArray category:
//CollectionViewController.m
#import "NSMutableArray+Shuffle.h"
- (void)viewDidLoad {
[super viewDidLoad];
self.cellArray = @[@"Type 1", @"Type 2", @"Type 3", ...];
NSIndexSet *beforeThirteen = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, 12)];
NSIndexSet *afterThirteen = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(13, self.cellArray.count-13)];
//Build an array with all objects except for the thirteenth one
NSMutableArray *arrayWithoutThirteenthObject = [NSMutableArray array];
[arrayWithoutThirteenthObject addObjectsFromArray:[self.cellArray objectsAtIndexes:beforeThirteen]];
[arrayWithoutThirteenthObject addObjectsFromArray:[self.cellArray objectsAtIndexes:afterThirteen]];
//Shuffle it
[arrayWithoutThirteenthObject shuffle];
//Add the thirteenth object into the shuffled array
[arrayWithoutThirteenthObject insertObject:self.cellArray[12] atIndex:12];
//Assign the shuffled array to the table view array
self.cellArray = arrayWithoutThirteenthObject;
}
At the end what I do is shuffle the array without the thirteenth object, and then add it back in at the thirteenth index after the array has been shuffled so in the end it is entirely shuffled save for the object at the thirteenth index, which has remained in the same place.
Just for accessibility's sake here's the code for the shuffle:
//NSMutableArray+Shuffle.h
@interface NSMutableArray (Shuffling)
- (void)shuffle;
@end
//NSMutableArray+Shuffle.m
@implementation NSMutableArray (Shuffling)
- (void)shuffle {
NSUInteger count = [self count];
for (NSUInteger i = 0; i < count; ++i) {
NSInteger nElements = count - i;
NSInteger n = (arc4random() % nElements) + i;
[self exchangeObjectAtIndex:i withObjectAtIndex:n];
}
}
@end
Upvotes: 2
Reputation: 17556
Sets are unordered and cannot contain duplicates so they are (almost) the perfect solution to your problem. Let's start by creating a set from your array.
NSSet *set = [NSSet setWithArray:self.cellArray];
Ok great, but how can get an object from this unordered set that cooresponds to our index path? We can only get objects from an NSSet using anyObject
. And that could give us the same object twice. Solution - make an ordered set.
NSOrderedSet *orderedSet = [NSOrderedSet orderedSetWithSet:set];
Then we can just pull out a unordered but ordered string from our set.
-(UICollectionViewCell*) collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
Cell * aCell = [collectionView dequeueReusableCellWithReuseIdentifier:@"bingoCell1" forIndexPath:indexPath];
aCell.cellContent.text = orderedSet[indexPath.row];
return aCell;
}
Upvotes: 0