Generate random index which is not generated again [duplicate] - objective-c

This question already has answers here:
Non repeating random numbers in Objective-C
(6 answers)
Closed 9 years ago.
I have an array of names and an array of numbers.
My Person class has a property for both the name and the number. I want to assign the random values to random people.
Suppose I have an array with the strings #"mary" , #"Jack" and #"ABhraham"
and another array with the numbers 122, 378, 987, I want to assign them these values randomly. I used the arc4random() method but it sometimes returns the same value again.

Use Fisher–Yates shuffle. Create an array that has numbers zero through N-1, inclusive, where N is the number of elements in your arrays; this will be the array of indexes. Then apply Fisher-Yates shuffle to the array of indexes. Now you can use number[index[i]] for each name[i].
Here is a link to an answer that provides a Fisher-Yates Shuffle implementation in Objective-C.

1: Use dictionaries, set keys for each person.
OR
2: Use mutable arrays for both, removing each object as you assign it.
while(arrayOfNumberTags.count>0){
float randomIndex = arc4random() % arrayOfNumberTags.count;
int tagForPerson = [arrayOfNumberTags objectAtIndex:randomIndex];
//Create the Person object with the tag and any person
[arrayOfNumberTags removeObjectAtIndex:randomIndex];
}

Related

Sort other arrays based on one array (Obj-C) [duplicate]

This question already has answers here:
Sorting two NSArrays together side by side
(4 answers)
Order two NSMutableArrays based on one
(2 answers)
Closed 5 years ago.
I have three NSMutableArray's:
NSMutableArray *dateArray;
NSMutableArray *nameArray;
NSMutableArray *imageArray
I would like to sort the dateArray based on the closest date, and then have the nameArray and imageArray bases on this new sorted order of the dateArray.
How can I accomplish this without changing the structure that I've already setup above?
Without considering why you have three arrays here is an algorithm to "sort" them together:
Create a new array the same size as your three arrays filled with integers starting from 0[†].
"Sort" this new array using sortedArrayUsingComparator: passing a block to the comparison.
Your block will get called with two values from the array, being two integers. Use those integers to index into dataArray and compare the values you find there, returning the result as the block result.
After this you will have an array of integers you can use to indirectly index into your three arrays, e.g. something like:
NSArray *sortedIndicies = [arrayOfInts sortedArrayUsingComparator:...];
// first item according to the sort
id firstDate = dateArray[sortedIndicies[0]];
id firstName = nameArray[sortedIndicies[0]];
You can of course use sortedIndicies to reorder your original 3 arrays if required.
There are other ways to achieve what you require, for example you can "zip" your three arrays into a single array of three items, sort, then "unzip" again. Zip operations are not provided by NSArray so you need to write them (both are a simple loop).
HTH
[†] You can use a "fake" array for this is you wish, for inspiration see this answer - your implementation could be simpler.

Associating a value with another value generated randomly

Here's what I'm looking to do:
I have a series of survey questions that are generated randomly for the user.
What I want is to associate two values with each other, the integer value of the question number that was generated randomly, and a integer value representative of how many times this user has answered this question. I want to be able to save and retrieve these associated values later so I can increment how many times the user has answered this question.
So, how do you associate two different integer values to each other, save, and update them later?
I'm starting with this code.
QuestionSelected = arc4random_uniform(4);
For example once this outcome was generated:
QuestionSelected = 1
I would need to establish a new value that I can associate with that question's value (1), increment it, and then save each time the user returns to this question.
Thanks for your help!
Association of one value with another is a "map". NSDictionary is the standard mapping collection in Cocoa, so you can use that:
NSNumber * timesSeen = myMutableDictionary[#(selectedQuestion)];
if( !timesSeen ){
timesSeen = #(0);
}
myMutableDictionary[#(selectedQuestion)] = #([timesSeen intValue] + 1);
Since an array in essence associates its indexes, which are numbers, with values, another option is to use an NSMutableArray:
NSNumber * timesSeen = myMutableArray[selectedQuestion];
myMutableArray[selectedQuestion] = #([timesSeen intValue] + 1);
An NSArray can't be sparse, so you would have to fill it up with zeroes when you create it:
for( NSUInteger i = 0; i < numQuestions; i++ ){
[myMutableArray addObject:#(0)];
}
As you may notice, dealing with numerical values that need to change in a Cocoa collection is a bit of a pain, because the NSNumbers have to be unboxed and replaced each time. So a third option would be a C array:
int * viewCounts;
viewCounts = calloc(numQuestions, sizeof(int));
viewCounts[selectedQuestion]++;
calloc() gets a chunk of memory for you and fills it with zeros. You will need to release that memory by calling free(viewCounts) when you are done with the array.

Random Number Generator Objective-C iOS8 [duplicate]

This question already has answers here:
Picking a Random Object in an NSArray
(8 answers)
Closed 8 years ago.
My app has a mutable array in a data model (used to pass data between views) which allows users to add the names of 'housemates' as strings to a table view controller. I want to later generate a random housemate in another view controller i.e. when a button is pressed I want the label underneath it to display the randomly selected housemate. I wondered if I could assign each housemate a number and, when a random number is generated, use an if/else statement to say something like:
if randomNumber == 0 {
self.label.text = self.housemate0.text;
}
But I'm unsure how to count all the housemates in the mutable array and then assign/tag them with a number to later be generated and how the actual code for generating the number/updating the label would work. Could anyone help me please? Many thanks.
A NSArray, or NSMutableArray is index based, so every entry has an unique index number to access it like myarray.objectAtIndex:1
And counting your array will be done by myarray.count
Is that what you expected with your question?!? :-)

How can I keep track of array index in for loop? [duplicate]

This question already has answers here:
how can I get the array index within an "for (id item in items)" objective-c loop?
(2 answers)
Closed 8 years ago.
If I write:
for (NSString* word in self.words)
{
}
And I want to keep track of my position in the array, how can I do that? Of course, I know I can just create an int and increment it as I loop, a.k.a. the old-fashioned way. I guess I'm just looking to see if there's an opportunity here to learn something. Like in python we have the handy enumerate() function for this sort of thing which gives you indices paired with objects.
You could use [words indexOfObject:word]; but caution: if you have equal object in an array, it will return the first object's index. also this shows, that it is awfully inefficient — if will iterate over the array for each call.
better:
[words enumerateObjectsUsingBlocks:^(NSString *word,
NSUInteger idx,
BOOL *stop)
{
//
}];
as it gives you enumeration AND the index at the same time.
documentation

How to build a C array like this dynamically in a loop, return it, and keep a reference?

Right now I have this setup:
An NSMutableArray which stores two NSMutableArray instances.
A for-loop walks over a set of data and writes values into these arrays. It's for a big diagram / chart which is going to be displayed with OpenGL ES.
The NSMutableArray containing two other NSMutableArray objects is returned by a method, and the caller assigns it to a retaining property.
The pitty is this: There can be up to 2.000 values, and I don't like to create all those NSNumber objects.
Now I hope there's a lightweight way to do this with C.
Before I walk the loop I know the number of data points.
Now I want to refactor this so that I get lightweight C-arrays that hold just plain old float values. I know how to create a C-array of float values, but not really dynamically:
CGFloat values[ ] = {
0, 2.5f,
30.2f, 2.5f,
50.95f, 200.55f,
930.2f, 122.1f,
};
Questions:
1) How can I create an array like this dynamically in a loop?
2) How would I put two of those arrays into one array?
3) What about the memory managament? The method returns that multidimensional C-array, and the receiver needs to assign that to an instance variable (property). It needs to be kept around for a while. How could I create an instance variable to hold such an C-array, without knowing it's exact size in advance?
For your first question, you can dynamically create an array using malloc(), and use a pointer variable to store a reference to the first element of it. For example, this will create an array of 8 CGFloats:
CGFloat *a = malloc(8 * sizeof a[0]);
If a is non-NULL, you can then access a[0] through a[7] in the usual way. You can return this CGFloat * value to another function, and when you are done with the array, you must pass this value to free().
For second question, you can create an array of two pointers to the two dynamic arrays:
CGFloat *a[2] = { NULL, NULL };
a[0] = malloc(8 * sizeof a[0][0]);
a[1] = malloc(16 * sizeof a[1][0]);
You can now access a[0][0] through a[0][7] and a[1][0] through a[1][15] (as long as a[0] and a[1] are not NULL).
However, there is a wrinkle here: You cannot directly return arrays in C, so you cannot return a from a function anymore. You could instead use two levels of dynamic arrays, but it probably makes more sense to store the array of pointers within the retaining object in the first place, and pass a reference to this array to the function that fills it in.
This means that your containing object would include the CGFloat *a[2] field, and your function that allocates the dynamic arrays and fills them would include a CFloat *dest[] parameter. That function would start with something like:
dest[0] = malloc(8 * sizeof dest[0][0]);
dest[1] = malloc(16 * sizeof dest[1][0]);
...and then fill in the values as normal.
For the third question, the array that is created by malloc() will live until that pointer is later passed to free(). As mentioned, you can happily return that value and store it elsewhere, as long as you don't free() it until you're done with it.
This will get you a new array:
CGFLoat* myArray = malloc(numberOfFloat * sizeof(float));
You can do things like myArray[6] = 0;.
When you're done with it, you have to call free(myArray), or you will have a memory leak.
With this in mind, your instance variable will just be a CGFloat*.