I've stored 4 unique numbers inside an NSMutableArray from 1-4. i've done that by using this code:
storeArray = [[NSMutableArray alloc] init];
BOOL record = NO;
int x;
for (int i=1; [storeArray count] < 4; i++) //Loop for generate different random values
{
x = arc4random() % 4;//generating random number
if(i==1)//for first time
{
[storeArray addObject:[NSNumber numberWithInt:x]];
}
else
{
for (int j=0; j<= [storeArray count]-1; j++)
{
if (x ==[[storeArray objectAtIndex:j] intValue])
record = YES;
}
if (record == YES)
{
record = NO;
}
else
{
[storeArray addObject:[NSNumber numberWithInt:x]];
}
}
}
I can then print the numbers out using storeArray[1] and so on.
the problem is i want to print the numbers inside this.
[option1 setTitle:questions[r][storeArray[0]] forState: UIControlStateNormal];
[option2 setTitle:questions[r][storeArray[1]] forState: UIControlStateNormal];
[option3 setTitle:questions[r][storeArray[2]] forState: UIControlStateNormal];
[option4 setTitle:questions[r][storeArray[3]] forState: UIControlStateNormal];
How can i do this?, cause i when i do this i get thread sigbrt error?
The problem is that your algorithm is faulty and when there are collisions because you are trying to keep the numbers unique, you don't record anything so your array might not always be the expected length. Actually there is a 91% chance of this happening in your case so it looks like it happens all the time.
Instead of trying to write your own algorithm, just use the existing classes. Simply use an NSSet to guarantee the uniqueness of the numbers in your array.
NSMutableSet *set = [[NSMutableSet alloc] init];
while(set.count < 4) {
int x = arc4random() % 4;
[set addObject:[NSNumber numberWithInteger:x]];
}
NSArray * storeArray = [set allObjects];
Related
I am trying to implement merge sort in objective -C.
This is a similar question asked in the following link , did not find it answered so creating a new question.
Merge sort in Objective-C
This is what I have tried ,
-(NSArray *)mergeSort:(NSArray *)unsortedArray {
if ([unsortedArray count] < 2)
return unsortedArray;
long mid = [unsortedArray count] / 2;
NSRange left = NSMakeRange(0, mid);
NSRange right = NSMakeRange(mid, [unsortedArray count] - mid);
NSArray *rightArray = [unsortedArray subarrayWithRange:right];
NSArray *leftArray = [unsortedArray subarrayWithRange:left];
NSArray *resultArray = [self merge:leftArray andRight:rightArray];
return resultArray;
}
-(NSArray *)merge:(NSArray *)leftArray andRight:(NSArray *)rightArray {
NSMutableArray *result = [NSMutableArray array];
int right = 0;
int left = 0;
while (left < [leftArray count] && right < [rightArray count]) {
NSComparisonResult comparisonResult = [leftArray[left] compare:rightArray[right]];
if (comparisonResult != NSOrderedDescending) {
[result addObject:[leftArray objectAtIndex:left++]];
} else {
[result addObject:[rightArray objectAtIndex:right++]];
}
/*if ([[leftArray objectAtIndex:left] intValue] < [[rightArray objectAtIndex:right] intValue]) {
[result addObject:[leftArray objectAtIndex:left++]];
//left++;
} else {
[result addObject:[rightArray objectAtIndex:right++]];
//right++;
}*/
}
NSRange leftRange = NSMakeRange(left, [leftArray count] - left);
NSRange rightRange = NSMakeRange(right, [rightArray count] - right);
NSArray * newRight = [rightArray subarrayWithRange:rightRange];
NSArray * newLeft = [leftArray subarrayWithRange:leftRange];
newLeft = [result arrayByAddingObjectsFromArray:newLeft];
return [newLeft arrayByAddingObjectsFromArray:newRight];
}
Kindly let me know if anyone has any other approaches for merge sort.
I dont understand why do you people want the long way.. Even though there are already easy way of doing this...
I made one myself hope this will help you..
- (NSArray *)arrayMergeSort:(NSArray *)targetArray
{
if (targetArray.count < 2)
return targetArray;
long midIndex = targetArray.count/2;
NSArray *arrayLeft = [targetArray subarrayWithRange:NSMakeRange(0, midIndex)];
NSArray *arrayRight= [targetArray subarrayWithRange:NSMakeRange(midIndex, targetArray.count - midIndex)];
return [self arrayMerge: [self arrayMergeSort:arrayLeft] : [self arrayMergeSort:arrayRight]];
}
For arrange merge:
- (NSArray *)arrayMerge:(NSArray *)arrayLeft :(NSArray *)arrayRight
{
NSMutableArray *resultArray = [[NSMutableArray alloc] init];
int i = 0, j = 0;
while (i < arrayLeft.count && j < arrayRight.count)
[resultArray addObject:([arrayLeft[i] intValue] < [arrayRight[j] intValue]) ? arrayLeft[i++] : arrayRight[j++]];
while (i < arrayLeft.count)
[resultArray addObject:arrayLeft[i++]];
while (j < arrayRight.count)
[resultArray addObject:arrayRight[j++]];
return resultArray;
}
And using it like:
//Sample array
NSArray *activeArray = #[#101,#201,#301,#121,#11,#123,#21,#14,#32,#76,#89,#987,#65];
NSLog(#"arrayMergeSort %#",[self arrayMergeSort:activeArray]);
Output would be:
And also this bubble sort if you needed this:
- (NSArray *)arrayBubbleSort:(NSArray *)targetArray
{
NSMutableArray *resultArray = [targetArray mutableCopy];
for (int k = 0; k < resultArray.count; k++)
{
for (int l = 0; l < resultArray.count; l++)
{
if ([resultArray[k] intValue] < [resultArray[l] intValue])
{
[resultArray exchangeObjectAtIndex:k withObjectAtIndex:l];
}
}
}
return resultArray;
}
Hope i've helped you.. Cheers..
You've made a simple mistake. Merge sort works my splitting the array, sorting to the two halves, then merging the results.
Your mergeSort: method does the split, doesn't sort the two halves, and then calls merge: to merge the two (unfortunately unsorted) halves.
Before calling merge: you need to make recursive calls to mergeSort: to sort the two halves - this is the simple step you missed out.
I'm guessing this in a learning exercise, so no code, but you're almost there (fix it and it does work).
BTW Once you've fixed it you might want to think about why you don't need to create new arrays for the split part (but its far easier to create a new array for the merges).
HTH
I am writing a recursive Sudoku solver and I am having some issues with 2D array handling. I included the function which is giving the trouble. There are some unnecessary lines I was using for debugging in there.
- (Stack *)successors
{
Stack *stack = [[Stack alloc] init];
NSMutableArray *temp = [[NSMutableArray alloc] init];
NSMutableArray *test = [[NSMutableArray alloc] init];
temp = [self.board copy];
for (int x = 0; x < columns; x++) {
for (int y = 0; y < rows; y++) {
if ([self.board[x][y] isEqualToString:#""] ||
[self.board[x][y] isEqualToString:#"."]) {
NSLog(#"%d %d", x, y);
for (int i = 1; i < 10; i++) {
NSLog(#"%d", i);
[temp[x] setObject:[NSString stringWithFormat:#"%d", i] atIndex:y];
State *tempState = [[State alloc] initWithBoard:temp];
if ([tempState legal]) {
NSMutableArray *input = [NSMutableArray arrayWithArray:temp];
[stack push:input];
[stack push:input];
[test addObject:input];
}
}
NSLog(#"test %#", test);
int p = [stack size];
for (int i = 0; i < p; i++) {
NSLog(#"%#", [stack pop]);
}
return stack;
}
}
}
return stack;
}
essentially, it begins at the top of the array and if the space is empty, it tries putting in the number 1 through 9 and if it is legal, based on another function I wrote previously, it will input it in the temp array and add it to the stack. I checked this and it works great. However, after adding them all together, I NSLog to check the stack and find that all of the stacked arrays now begin with the number 9, the last number checked in the temp array. I believe I am having some issue with keeping reference to the temp array, but I cannot figure it out. Any help is great.
This question already has answers here:
combinations of a set with given number elements
(2 answers)
Closed 9 years ago.
I have 9 tiles labeled 1-9 with corresponding values. Tile 1=1, tile 6=6, etc. A user can press down tiles that equal the sum of the die. When they press confirm move, those tales can not be used anymore.
I need to compute every possible combination of numbers to check whether or not the user can go again. Currently I am computing it like this, but I'm sure there has to be a better way.
allTiles contains the tiles that are still available to be computed.
What would be the best way to check for all combinations?
- (void) getCombinations {
NSMutableArray *combinations = [[NSMutableArray alloc] init];
for (int i = 0; i < [allTiles count]; i++) {
for (int j = i + 1; j < [allTiles count]; j++) {
for (int k = i+2; k < [allTiles count]; k++) {
TileView *first = [allTiles objectAtIndex:i];
TileView *second = [allTiles objectAtIndex:j];
TileView *third = [allTiles objectAtIndex:k];
NSNumber *total = [NSNumber numberWithInt:first.getTileValue + second.getTileValue];
NSNumber *total2 = [NSNumber numberWithInt:
first.getTileValue +
second.getTileValue +
third.getTileValue];
[combinations addObject:[NSNumber numberWithInt:first.getTileValue]];
[combinations addObject:[NSNumber numberWithInt:second.getTileValue]];
[combinations addObject:[NSNumber numberWithInt:third.getTileValue]];
[combinations addObject:total];
[combinations addObject:total2];
}
}
}
if ([combinations containsObject:[NSNumber numberWithInt:[self diceTotal]]]) {
NSLog(#"STILL COMBINATION AVAILABLE");
}
else {
NSString *message = [NSString stringWithFormat:#"Your score: %i", player1Score];
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:#"No more combinations left."
message: message
delegate:self
cancelButtonTitle:#"Go to player2"
otherButtonTitles: nil];
[alert show];
[alert release];
}
}
Here is a a screenshot of one of scenarios where my method doesn't work.
In your example, there are four tiles available to the player. Whether or not to include a tile is a binary choice (YES or NO), and there are 4 such choices in this example, so there are 2×2×2×2 = 24 possible combinations of tiles. In general, there are 2n combinations where there are n tiles available.
The simplest way to check for a combination that sums to your target is simply to enumerate the integers from 0 through 2n. For each integer i, write i in binary and add up the tile values of the tiles corresponding to the 1's of the binary representation.
We'll cache the tile values in a local array to avoid sending the tileValue message over and over.
static int selectedNumbersSum(unsigned int selector, int const *numbers) {
int sum = 0;
for (int i = 0; selector != 0; i += 1, selector >>= 1) {
if (selector & 1) {
sum += numbers[i];
}
}
return sum;
}
static BOOL tilesCanMakeTarget(NSArray *tiles, int target) {
NSUInteger count = tiles.count;
int numbers[count];
for (int i = 0; i < count; ++i) {
numbers[i] = [tiles[i] tileValue];
}
for (unsigned int step = 0, maxStep = 1 << count; step < maxStep; ++step) {
if (selectedNumbersSum(step, numbers) == target)
return YES;
}
return NO;
}
- (void)checkForEndOfPlayer1Turn {
if (tilesCanMakeTarget(allTiles, self.diceTotal)) {
NSLog(#"STILL COMBINATION AVAILABLE");
} else {
NSString *message = [NSString stringWithFormat:#"Your score: %i",
player1Score];
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:#"No more combinations left."
message:message delegate:self cancelButtonTitle:#"Go to player 2"
otherButtonTitles:nil];
[alert show];
[alert release];
}
}
Incidentally, we don't usually start our getter method names with get. Your getCombinations method should probably be called checkCombinations (or something like that) since it's not even a getter. And your getTileValue method should just be called tileValue.
I am trying to randomize numbers in an array. I am able to do that using arc4random() % [indexes count]
My problem is - If an array consists of 20 items, every time the array shuffles, in a batch of 5, different number should appear. Example :
first shuffle: 1,4,2,5,6.
second shuffle: 7,12,9,15,3
-(IBAction)randomNumbers:(UIButton *)sender
{
int length = 10; // int length = [yourArray count];
NSMutableArray *indexes = [[NSMutableArray alloc] initWithCapacity:length];
for (int i=0; i<5; i++)
[indexes addObject:[NSNumber numberWithInt:i]];
NSMutableArray *shuffle = [[NSMutableArray alloc] initWithCapacity:length];
while ([indexes count])
{
int index = arc4random() % [indexes count];
[shuffle addObject:[indexes objectAtIndex:index]];
[indexes removeObjectAtIndex:index];
}
// for (int i=0; i<[shuffle count]; i++)
NSLog(#"%#", [shuffle description]);
}
As per your requirement....kindly check this code
Make this a property
#synthesize alreadyGeneratedNumbers;
Add these methods in your .m
-(int)generateRandomNumber{
int TOTAL_NUMBER=20;
int low_bound = 0;
int high_bound = TOTAL_NUMBER;
int width = high_bound - low_bound;
int randomNumber = low_bound + arc4random() % width;
return randomNumber;
}
-(IBAction)randomNumbers:(UIButton *)sender
{
NSMutableArray *shuffle = [[NSMutableArray alloc] initWithCapacity:5];
BOOL contains=YES;
while ([shuffle count]<5) {
NSNumber *generatedNumber=[NSNumber numberWithInt:[self generateRandomNumber]];
//NSLog(#"->%#",generatedNumber);
if (![alreadyGeneratedNumbers containsObject:generatedNumber]) {
[shuffle addObject:generatedNumber];
contains=NO;
[alreadyGeneratedNumbers addObject:generatedNumber];
}
}
NSLog(#"shuffle %#",shuffle);
NSLog(#"Next Batch");
if ([alreadyGeneratedNumbers count] >= TOTAL_NUMBER) {
NSLog(#"\nGame over, Want to play once again?");//or similar kind of thing.
[alreadyGeneratedNumbers removeAllObjects];
}
}
Still I feel you need to some changes like
it will give you correct value, but what if user pressed 5th time?
out of 20 numbers you already picked 4 sets of 5 number, on on 6th time it will be in loop to search for next set of numbers and will become infinite.
So what you can do is, keep the track of shuffle and once it reaches the limit i.e, 20/5=4 disable the random button.
Declare array that contains already generated number in extension or header file
#property (strong, nonatomic)NSMutableArray *existingNums;
#property (assign, nonatomic)NSInteger maxLimit;
#property (assign, nonatomic)NSInteger minLimit;
Then implement given code in implementation file
#synthesize existingNums;
#synthesize maxLimit;
#synthesize minLimit;
- (NSInteger)randomNumber {
if(!existingNums)
existingNums = [NSMutableArray array];
while (YES) {
NSNumber *randonNum = [NSNumber numberWithInteger:minLimit+arc4random()%maxLimit];
if([existingNums containsObject:randonNum]) {
if([existingNums count] == (maxLimit - minLimit))
return -1; // All possible numbers generated in the given range
continue;
}
[existingNums addObject:randonNum];
return [randonNum integerValue];
}
return -1; // return error
}
Hope this will help you :)
This one works for me:
NSMutableArray *numbers = [NSMutableArray new];
BOOL addElement = YES;
int limit = 100; // Range from 0 to 36
int numElem = 10; // Number of elements
do
{
int ranNum = (arc4random() % limit) +1;
if ([numbers count] < numElem) {
for (NSNumber *oneNumber in numbers) {
addElement =([oneNumber intValue] != ranNum) ? YES:NO;
if (!addElement) break;
}
if (addElement) [numbers addObject:[NSNumber numberWithInt:ranNum]];
} else {
break;
}
} while (1);
NSLog(#"%#",numbers);
The problem with all these answers is that you need to review your previous generated random numbers and that takes extra time if you need a large number of random integers.
Another solution is using cryptography:
Generate a random key
Iterate between 0..n
Encrypt each integer and apply modulo the number of alternatives do you want to use to the output of the function.
There are some extra details to take into account that don't matter for your case.
self.myArray = [NSArray arrayWithObjects: [NSArray arrayWithObjects: [self generateMySecretObject], [self generateMySecretObject],nil], [NSArray arrayWithObjects: [self generateMySecretObject], [self generateMySecretObject],nil],nil];
for (int k=0; k<[self.myArray count]; k++) {
for(int s = 0; s<[[self.myArray objectAtIndex:k] count]; s++){
[[[self.myArray objectAtIndex:k] objectAtIndex:s] setAttribute:[self generateSecertAttribute]];
}
}
As you can see this is a simple 2*2 array, but it takes me lots of code to assign the NSArray in very first place, because I found that the NSArray can't assign the size at very beginning. Also, I want to set attribute one by one. I can't think of if my array change to 10*10. How long it could be. So, I hope you guys can give me some suggestions on shorten the code, and more readable. thz
(Some Assumptions: myArray will have a fixed size. It won't grown up or become smaller in the run time.)
Generate the array by -addObject:.
NSMutableArray* myArray = [NSMutableArray array];
for (int k = 0; k < 10; ++ k) {
NSMutableArray* subArr = [NSMutableArray array];
for (int s = 0; s < 10; ++ s) {
id item = (s == 0 && k == 0) ? [self d] : [self generateMySecretObject];
[item setAttribute:[self generateSecertAttribute]];
[subArr addObject:item];
}
[myArray addObject:subArr];
// use [myArray addObject:[[subArr copy] autorelease]] for deep immutability.
}
return [[myArray copy] autorelease];
(Don't query self.myArray many times. Each corresponds to an ObjC call and while someone calls an ObjC call is cheap, it's still not free.)
If the array is a fixed size and each row is the same length then you could uses a 1D array and an offset, EG:
int rowLength = 5;
int rowNumber = 0;
int columnNumber = 3;
[myArray objectAtIndex: (rowLength * rowNumber) + columnNumber];