I would like to have user click on a button to generate a ten-question quiz in the form of "a +/- b = c" where the values for a and b are from +10 to -10 and are randomly assigned for the ten questions. Also, the questions should randomly switch between addition and subtraction. How do I populate the plist file correctly? How do I use arc4random to create ten questions with random integers?
I thought it would be neat to have questions display in a one-column picker where user can scroll through the questions or just have text at a certain CGPoint on screen.
Instead, I have created a plist with 84 different possible questions and I want to randomly choose 10 from plist to create the quiz each time a user clicks on button. I have this so far:
NSString *plistFile = [[NSBundle mainBundle] pathForResource:#"global" ofType:#"plist"];
NSDictionary *dict = [NSDictionary dictionaryWithContentsofFile:plistFile];
NSLog(#"%#",[dict objectForKey:#"1"]);
NSLog(#"%#",[dict objectForKey:#"2"]);
NSLog(#"%#",[dict objectForKey:#"3"]);
global is the name of plist, #"1", #"2", #"3" etc are the names of the 84 diff Q's I put in plist. How do I randomly choose 10 of the 84 NSLogs?
Instead of using a NSDictionary, use NSArray if your keys are just numbers. You could then do
NSString *randomString = [array objectAtIndex:(arc4random() % [array count])];
to pick a random element.
However, I would really advice against looking it up in a plist if it's just different combinations of random numbers. Writing out all those combinations by hand is just a waste of time. That's what computers are for!
Old, but still relevant answer:
To generate a random number between -10and 10:
int a = (arc4random() % 21) - 10;
You could also make a function like this:
int randomIntegerInRange(int min, int max)
{
int range = max - min + 1;
return min + arc4random() % range;
}
Related
So my friend asked me this question as interview practice:
Using Objective-C & Foundation Kit, Write a method that takes a single digit int, and logs out to the console the precise result of that int being raised to the power of 100.
Initially I thought it sounded easy, but then I realized that even a single digit number raised to the power of 100 would quickly come close to 100 digits, which would overflow.
So I tried tackling this problem by creating an NSArray w/ NSNumbers (for reflection), where each object in the array is a place in the final result number. Then I perform the multiplication math (including factoring in carries), and then print out a string formed by concatenating the objects in the array. Here is my implementation w/ input 3:
NSNumber *firstNum = [NSNumber numberWithInteger:3];
NSMutableArray *numArray = [NSMutableArray arrayWithArray:#[firstNum]];
for( int i=0; i<99; i++)
{
int previousCarry = 0;
for( int j=0; j<[numArray count]; j++)
{
int newInt = [firstNum intValue] * [[numArray objectAtIndex:j] intValue] + previousCarry;
NSNumber *calculation = [NSNumber numberWithInteger:newInt];
previousCarry = [calculation intValue]/10;
NSNumber *newValue = [NSNumber numberWithInteger:(newInt % 10)];
[numArray replaceObjectAtIndex:j withObject:newValue];
}
if(previousCarry > 0)
{
[numArray addObject:[NSNumber numberWithInteger:previousCarry]];
}
}
NSArray* reversedArray = [[numArray reverseObjectEnumerator] allObjects];
NSString *finalNumber = [reversedArray componentsJoinedByString:#""];
NSLog(#"%#", finalNumber);
This isn't a problem out of a textbook or anything so I don't have any reference to double check my work. How does this solution sound to you guys? I'm a little worried that it's pretty naive even though the complexity is O(N), I can't help but feel like I'm not utilizing a type/class or method unique to Objective-C or Foundation Kit that would maybe produce a more optimal solution-- or at the very least make the algorithm cleaner and look more impressive
Write a method that takes a single digit int, and logs out to the console the precise result of that int being raised to the power of 100.
That strikes me as a typical interview "trick"[*] question - "single digit", "logs out to console"...
Here goes:
NSString *singleDigitTo100(int d)
{
static NSString *powers[] =
{
#"0",
#"1",
#"1267650600228229401496703205376",
#"515377520732011331036461129765621272702107522001",
#"1606938044258990275541962092341162602522202993782792835301376",
#"7888609052210118054117285652827862296732064351090230047702789306640625",
#"653318623500070906096690267158057820537143710472954871543071966369497141477376",
#"3234476509624757991344647769100216810857203198904625400933895331391691459636928060001",
#"2037035976334486086268445688409378161051468393665936250636140449354381299763336706183397376",
#"265613988875874769338781322035779626829233452653394495974574961739092490901302182994384699044001"
};
return powers[d % 10]; // simple bounds check...
}
And the rest is easy :-)
And if you are wondering, those numbers came from bc - standard command line calculator in U*ix and hence OS X. You could of course invoke bc from Objective-C if you really want to calculate the answers on the fly.
[*] It is not really a "trick" question but asking if you understand that sometimes the best solution is a simple lookup table.
As you have correctly figured out, you will need to use some sort of big integer library. This is a nice example you can refer to: https://mattmccutchen.net/bigint/
Furthermore, you can calculate x^n in O(lg(n)) rather than in O(n), using divide and conquer:
f(x, n):
if n == 0: # Stopping condition
return 1
temp = f(n/2)
result = temp * temp
if n%2 == 1:
result *= x
return result
x = 5 # Or another one digit number.
n = 100
result = f(x, 100) # This is the result you are looking for.
Note that x represents your integer and n the power you are raising x to.
I've been trying to get non-repeating arc4random_uniform to work for ages now for my iPhone app. Been over all the questions and answers relating to this on stackoverflow with no luck and now I'm hoping someone can help me. What I want to do is is choose 13 different random numbers between 1 and 104. I have gotten it to work to the point of it choosing 13 different numbers, but sometimes two of them are the same.
int rand = arc4random_uniform(104);
This is what I'm doing, and then I'm using the rand to choose from an array. If it's easier to shuffle the array and then pick 13 from the top, then I'll try that, but I would need help on how to, since that seems harder.
Thankful for any advice.
There's no guarantee whatsoever that ar4random_uniform() won't repeat. Think about it for a second -- you're asking it to produce a number between 0 and 103. If you do that one hundred and five times, it has no choice but to repeat one of its earlier selections. How could the function know how many times you're going to request a number?
You will either have to check the list of numbers that you've already gotten and request a new one if it's a repeat, or shuffle the array. There should be any number of questions on SO for that. Here's one of the oldest: What's the Best Way to Shuffle an NSMutableArray?.
There's also quite a few questions about non-repeating random numbers: https://stackoverflow.com/search?q=%5Bobjc%5D+non-repeating+random+numbers
You can create an NSMutableSet and implement it like this:
NSMutableArray* numbers = [[NSMutableArray alloc] initWithCapacity: 13];
NSMutableSet* usedValues = [[NSMutableSet alloc] initWithCapacity: 13];
for (int i = 0; i < 13; i++) {
int randomNum = arc4random_uniform(104);
while ([usedValues containsObject: [NSNumber numberWithInt: randomNum]) {
randomNum = arc4random_uniform(104)
}
[[usedValues addObject: [NSNumber numberWithInt: randomNum];
[numbers addObject: [[NSNumber numberWithInt: randomNum];
}
Alternatively you can also create a mutable array of 105 integers each a unique one, and arc4random_uniform([arrayname count]) and then delete that same one from the array, then you'll get a random int each time without repeating (though the smaller the array gets the easier it is to predict what the next number will be, just simple probability)
The best algorithm that I have found for this exact question is described here:
Algorithm to select a single, random combination of values?
Instead of shuffling an array of 104 elements, you just need to loop through 13 times. Here is my implementation of the algorithm in Objective C:
// Implementation of the Floyd algorithm from Programming Pearls.
// Returns a NSSet of num_values from 0 to max_value - 1.
static NSSet* getUniqueRandomNumbers(int num_values, int max_value) {
assert(max_value >= num_values);
NSMutableSet* set = [NSMutableSet setWithCapacity:num_values];
for (int i = max_value - num_values; i < max_value; ++i) {
NSNumber* rand = [NSNumber numberWithInt:arc4random_uniform(i)];
if ([set containsObject:rand]) {
[set addObject:[NSNumber numberWithInt:i]];
} else {
[set addObject:rand];
}
}
return set;
}
I'm new to programming, I have some basic python programming from college, I am familiar with some of the OOP basics and would like some help with managing large amounts of integers. I have 88 of them. 7 will be used for capturing user input and the other 81 will be used for a specific calculation. Instead of writing the following code:
int currentPlace;
int futurePlace;
int speed;
int distance;
int place1 = 1;
int place2 = 2;
int place3 = 3;
// etc...
int place81 = 81;
And then later coming back to the integers and asking user defined questions such as:
NSLog(#"What place is the runner in?");
scanf("%i", ¤tPlace);
NSLog(#"What place does the runner finish in?");
scanf("%i", &futurePlace);
NSLog(#"What is the distance of the track?");
// doing some math
NSLog(#"The runner is running at "i" MPH.",speed);
I remember there being an easier way to use the integers but I keep thinking enums or typedefs.
I'd like for the user to pick a number and not have to run a huge if statement to get the work done to cut the size of the program as much as possible.
This is my first "on my own" application so any helpful pointers would be great.
Thanks.
I haven't understood why you need all these place's, but I also assume that an array would be easier to use here. You can use either NSArray or NSMutableArray. The difference between them is that an NSArray instance can't be changed after being created (you can't add/remove elements) unlike an NSMutableArray.
Using NSArray
NSArray *places = [NSArray arrayWithObjects:[NSNumber numberWithInt:1], [NSNumber numberWithInt:2],[NSNumber numberWithInt:3], ..., [NSNumber numberWithInt:81], nil];
nil at the end means the end of the contents of an array. [NSNumber numberWithInt:1] returns an int given as an argument (we can't straight give an int to the array, as an array expects an object as an argument.
You can access the contents of the array using:
[places objectAtIndex:(NSUInteger)];
Remeber that an array starts counting with 0, so if you want to get 5, you have to do this
[places objectAtIndex:4];
Using NSMutableArray
I suggest that you should use this option.
It's easier to use for here.
NSMutableArray *places = [NSMutableArray array];
for (int i = 1; i < 81; i++)
{
[places addObject:[NSNumber numberWithInt:i]];
}
Then you can access data the same way as in the NSArray:
[places objectAtIndex:0];
This will return 1. You can start the for-cycle with 0. After that the index of an array will correspond to the integer inside, so
[places objectAtIndex:5];
will actually return 5.
Are you thinking of a C array?
int myPlaces[81];
for (int i=0; i<81; i++) {
myPlaces[i] = 0;
}
There are lots of examples on this site about adding to NSMutableArray and I have looked at many but I still don't either understand (highly possible) or am missing something fundamental.
I am trying to add to an NSMutableArray via a for loop. I want to keep track of button x,y coordinate position using the button tag as key/index so I can change a button as a user clicks it. This is all without IB.
My init is as follow:
self.tmpXpos = [[NSMutableArray alloc] init];
self.tmpYpos = [[NSMutableArray alloc] init];
[self.tmpXpos insertObject:[NSNull null] atIndex:0];
[self.tmpYpos insertObject:[NSNull null] atIndex:0];
**I added these after reading about 'creating' the array and populating it with null.
In the loop:
NSUInteger btag = button.tag; //NSUInterger as per help
>>NSNumber *xNumber = [NSNumber numberWithInteger:[self xpos]]; // NSNumber as an Object wrapper
>>NSNumber *yNumber = [NSNumber numberWithInteger:[self ypos]];
>>[self.tmpXpos insertObject:xNumber atIndex:btag];
>>[self.tmpYpos insertObject:yNumber atIndex:btag];
NSLog(#"%d, %#, %#",btag,xNumber,yNumber);
The log entries look ok:
2,64,0
3,128,0
etc for each button to be added to the screen.
During debugging - the tmpXpos and tmpYpos listed as " 0 Objects " under self.
I retrieve the information thusly:
NSUInteger tmpSt = [self.sTags integerValue];
NSNumber *tmpX = [self.tmpXpos objectAtIndex:tmpSt];
NSNumber *tmpY = [self.tmpYpos objectAtIndex:tmpSt];
int tmpPositionX = [tmpX intValue];
int tmpPositionY = [tmpY intValue];
NSLog(#"%d, %d",tmpPositionX, tmpPositionY);
NSLog yields 0, 0
I do appreciate any guidance or questions you folks might have as this site's 'sanity checks' have saved my bacon in the past.
I am ignoring memory leaks as of yet, but they are in the back of my mind. No worries there.
Ironically, I have a couple of other arrays that work just fine, but the exception is that they are not populated via a loop.
Lastly, the code works fine as the button at location 0,0 does change as per design, LOL, but not for any other location.
Thanks again!
Neil
I think your problem is that you are creating the NSNumbers with the method numberWithInteger, when an NSUInteger is actually an unsigned long. So try
xNumber = [NSNumber numberWithUnsignedLong:[self xpos]];
Trees for the forest answer. I wanted to populate an array with a quantity, however, the array expects that quantity to be in numerical sequence. My data didn't have any 'gaps' but wasn't in sequence either; I.E., 1,2,3,6,7,12 etc. So, as user397313 helped me see, NSDictionary is the way to go with that kind of datum.
I've written a small utility program that identifies duplicate tracks in iTunes.
The actual matching of tracks takes a long time, and I'd like to optimize it.
I am storing track data in an NSMutableDictionary that stores individual track data in
NSMutableDictionaries keyed by trackID. These individual track dictionaries have
at least the following keys:
TrackID
Name
Artist
Duration (in milli ####.####)
To determine if any tracks match one another, I must check:
If the duration of two tracks are within 5 seconds of each other
Name matches
Artist matches
The slow way for me to do it is using two for-loops:
-(void)findDuplicateTracks {
NSArray *allTracks = [tracks allValues];
BOOL isMatch = NO;
int numMatches = 0;
// outer loop
NSMutableDictionary *track = nil;
NSMutableDictionary *otherTrack = nil;
for (int i = 0; i < [allTracks count]; i++) {
track = [allTracks objectAtIndex:i];
NSDictionary *summary = nil;
if (![claimedTracks containsObject:track]) {
NSAutoreleasePool *aPool = [[NSAutoreleasePool alloc] init];
NSUInteger duration1 = (NSUInteger) [track objectForKey:kTotalTime];
NSString *nName = [track objectForKey:knName];
NSString *nArtist = [track objectForKey:knArtist];
// inner loop - no need to check tracks that have
// already appeared in i
for (int j = i + 1; j < [allTracks count]; j++) {
otherTrack = [allTracks objectAtIndex:j];
if (![claimedTracks containsObject:otherTrack]) {
NSUInteger duration2 = (NSUInteger)[otherTrack objectForKey:kTotalTime];
// duration check
isMatch = (abs(duration1 - duration2) < kDurationThreshold);
// match name
if (isMatch) {
NSString *onName = [otherTrack objectForKey:knName];
isMatch = [nName isEqualToString:onName];
}
// match artist
if (isMatch) {
NSString *onArtist = [otherTrack objectForKey:knArtist];
isMatch = [nArtist isEqualToString:onArtist];
}
// save match data
if (isMatch) {
++numMatches;
// claim both tracks
[claimedTracks addObject:track];
[claimedTracks addObject:otherTrack];
if (![summary isMemberOfClass:[NSDictionary class]]) {
[track setObject:[NSNumber numberWithBool:NO] forKey:#"willDelete"];
summary = [self dictionarySummaryForTrack:track];
}
[otherTrack setObject:[NSNumber numberWithBool:NO] forKey:#"willDelete"];
[[summary objectForKey:kMatches]
addObject:otherTrack];
}
}
}
[aPool drain];
}
}
}
This becomes quite slow for large music libraries, and only uses 1
processor. One recommended optimization was to use blocks and process
the tracks in batches (of 100 tracks). I tried that. If my code
originally took 9 hours to run, it now takes about 2 hours on a
quad-core. That's still too slow. But (talking above my pay grade here)
perhaps there is a way to store all the values I need in a C structure that "fits on the stack" and then I wouldn't have to fetch the values from slower memory. This seems too low-level for me, but I'm willing to learn if I had an example.
BTW, I profiled this in Instruments and [NSCFSet member:] takes up
86.6% percent of the CPU time.
Then I thought I should extract all the durations into a sorted array so I would not have
to look up the duration value in the dictionary. I think that is a good
idea, but when I started to implement it, I wondered how to determine
the best batch size.
If I have the following durations:
2 2 3 4 5 6 6 16 17 38 59 Duration
0 1 2 3 4 5 6 7 8 9 10 Index
Then just by iterating over the array, I know that to find matching
tracks of the song at index 0, I only need to compare it against songs
up to index 6. That's great, I have my first batch. But now I have to
start over at index 1 only to find that it's batch should also stop at
index 6 and exclude index 0. I'm assuming I'm wasting a lot of
processing cycles here determining what the batch should be/the duration
matches. This seemed like a "set" problem, but we didn't do much of
that in my Intro to Algorithms class.
My questions are:
1) What is the most efficient way to identify matching tracks? Is it
something similar to what's above? Is it using disjoint and [unified]
set operations that are slightly above my knowledge level? Is it
filtering arrays using NSArray? Is there an online resource that
describes this problem and solution?
I am willing to restructure the tracks dictionary in whatever way
(datastructure) is most efficient. I had at first thought I needed to
perform many lookups by TrackID, but that is no longer the case.
2) Is there a more efficient way to approach this problem? How do you
rock stars go from paragraph 1 to an optimized solution?
I have searched for the answer, longer than I care to admit, and found
these interesting, but unhelpful answers:
find duplicates
Find all duplicates and missing values in a sorted array
Thanks for any help you can provide,
Lance
My first thought is to maintain some sorted collections as indices into your dictionary so you can stop doing an O(n^2) search comparing every track to every other track.
If you had arrays of TrackIDs sorted by duration then for any track you could do a more efficient O(log n) binary search to find tracks with durations within your 5 second tolerance.
Even better for artist and name you can store a dictionary keyed on the artist or track name whose values are arrays of TrackIDs. Then you only need a O(1) lookup to get the set of tracks for a particular artist which should allow you to very quickly determine if there are any possible duplicates.
Finally if you've built that sort of dictionary of titles to TrackIDs then you can go through all of it's keys and only search for duplicates when there are multiple tracks with the same title. Doing further comparisons only when there are multiple tracks with the same title should eliminate a significant percentage of the library and massively reduce your search time (down to O(n) to build the dictionary and another O(n) for a worst case search for duplicates still leaves you at O(n) rather than the O(n^2) you have now).
If nothing else do that last optimization, the resulting performance increase should be huge for an library without a significant number of duplicates:
NSMutableArray *possibleDuplicates = [NSMutableArray array];
NSMutableDictionary *knownTitles = [NSMutableDictionary dictionary];
for (NSMutableDictionary *track in [tracks allKeys]) {
if ([knownTitles objectForKey:[track objectForKey:#"title"]] != nil) {
[possibleDuplicates addObject:track];
}
else {
[knownTitles addObject:[track objectForKey:#"TrackID"] forKey:[track objectForKey:#"title"]];
}
}
//check for duplicates of the tracks in possibleDuplicates only.
There are several ways to do this, but here's my first naïve guess:
Have a mutable dictionary.
The keys in this dictionary are the names of the songs.
The value of each key is another mutable dictionary.
The keys of this secondary mutable dictionary are the artists.
The value of each key is a mutable array of songs.
You'd end up with something like this:
NSArray *songs = ...; //your array of songs
NSMutableDictionary *nameCache = [NSMutableDictionary dictionary];
for (Song *song in songs) {
NSString *name = [song name];
NSMutableDictionary *artistCache = [nameCache objectForKey:name];
if (artistCache == nil) {
artistCache = [NSMutableDictionary dictionary];
[nameCache setObject:artistCache forKey:name];
}
NSString *artist = [song artist];
NSMutableArray *songCache = [artistCache objectForKey:artist];
if (songCache == nil) {
songCache = [NSMutableArray array];
[artistCache setObject:songCache forKey:artist];
}
for (Song *otherSong in songCache) {
//these are songs that have the same name and artist
NSTimeInterval myDuration = [song duration];
NSTimeInterval otherDuration = [otherSong duration];
if (fabs(myDuration - otherDuration) < 5.0f) {
//name matches, artist matches, and their difference in duration is less than 5 seconds
}
}
[songCache addObject:song];
}
This is a worst-case O(n2) algorithm (if every song has the same name, artist, and duration). It's a best-case O(n) algorithm (if every song has a different name/artist/duration), and will realistically end up being closer to O(n) than to O(n2) (most likely).