Have an NSMutableArray, and when my users press a button, I'd like all items in the array to randomly change position, !! except for the first !!.
Right now I have
-(void)shufflemyList{
NSLog(#"Un Shuffled array : %#",myList);
NSMutableArray *array = [NSMutableArray arrayWithCapacity:0];
while ([myList count] > 0)
{
int index = arc4random() % [myList count];
id objectToMove = [myList objectAtIndex:index];
[array addObject:objectToMove];
[myList removeObjectAtIndex:index]; }
// test
NSLog(#"Shuffled array : %#",array);
myList=array; }
This works to completely shuffle the list.
Is there a way to shuffle the whole list, excepting the first item?
Just add 2 lines
-(void)shufflemyList{
NSLog(#"Un Shuffled array : %#",myList);
NSMutableArray *array = [NSMutableArray arrayWithCapacity:0];
// new code ---
[array addObject:myList[0]];
[myList removeObjectAtIndex:0];
// ---
while ([myList count] > 0)
{
int index = arc4random() % [myList count];
id objectToMove = [myList objectAtIndex:index];
[array addObject:objectToMove];
[myList removeObjectAtIndex:index]; }
// test
NSLog(#"Shuffled array : %#",array);
myList=array; }
Also it is better to use 'arc4random_uniform(n)' instead of 'arc4random() % n'. From docs:
arc4random_uniform() will return a uniformly distributed random number
less than upper_bound. arc4random_uniform() is recommended over
constructions like ``arc4random() % upper_bound'' as it avoids "modulo
bias" when the upper bound is not a power of two.
Related
Objective: compare values stored in Mutable array(which are changing constantly) to the index of a static Array. When the values match I would like to add the object(s) of the static array to a new mutable array.
Example:
Values of MutableArray at present state:
(1,2,3)
(Index) - Values of Static Array:
(0) - "Zero"
(1) - "One"
(2) - "Two"
(3) - "Three"
(4) - "Four"
Take values from initial MutableArray and compare them to the static array index's. Output the values at those index's to a new MutableArray
("One","Two","Three")
The initial array is derived by passing the MutableArrayContents for a search via predicate into this:
NSMutableArray *indexArray = [NSMutableArray array];
for (NSMutableArray* obj in _searchResults)
{
if([_questionsArray containsObject:obj] && ![indexArray containsObject:obj])
[indexArray addObject:#([_questionsArray indexOfObject:obj])];
}
IndexArray is the array of "index's".
I've tried for loops but they are not working correctly, any help would be appreciated.
Thanks!
You can try this:
NSArray *staticArr = #[#"Zero",#"One",#"Two",#"Three",#"Four"];
NSArray *otherArr = #[#1,#2,#3];
NSMutableArray * array = [[NSMutableArray alloc] initWithCapacity:[otherArr count]];
for(int i = 0; i < [staticArr count]; i++) {
for(int j = 0; j < [otherArr count]; j++) {
if([[otherArr objectAtIndex:j] intValue] == i) {
[array insertObject:[staticArr objectAtIndex:i] atIndex:j];
break;
}
}
}
Try this method
NSArray *staticArr = #[#"Zero", #"One", #"Two", #"Three", #"Four"];
NSArray *otherArr = #[#(1), #(2), #(3)];
NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:[otherArr count]];
[staticArr enumerateObjectsUsingBlock:^(NSString *string, NSUInteger staticIndex, BOOL *staticStop) {
[otherArr enumerateObjectsUsingBlock:^(NSNumber *number, NSUInteger index, BOOL *stop) {
if (number.integerValue == staticIndex) {
[array insertObject:string atIndex:index];
}
}];
}];
I am typing this on a tab. Please forgive any formatting issues
NSMutableArray *indices; //I am omitting the adding of data, it contains required indices as NSNumber objects
NSArray *staticArr = #[#"One", #"Two", #"Three", #"Four", #"Five"];
NSMutableArray *array = [NSMutableArray new];
for(NSNumber *index in indices) {
NSInteger idx = [index integerValue];
If(idx < staticArr.count)
{
[array addObject:[staticArr objectAtIndex:idx];
}
}
This will be in the order of the elements in indices array and may have repetitions in case there are repetitions in indices array.
This is the most straightforward way, there are many ways to get the subarray using Apple's API
I have an NSArray with 4 objects, let's say 1, 2, 3 and 4. I want to sort this array in ascending order, but with a randomly selected starting number. For instance; 2, 3, 4 and 1 or 4, 1, 2 and 3.
How can I do this?
What I have thus far:
NSArray *playersArray = [_players allKeys];
NSSortDescriptor *sortPlayerArray = [[NSSortDescriptor alloc] initWithKey:nil ascending:YES];
playersArray = [playersArray sortedArrayUsingDescriptors:#[sortPlayerArray]];
This results in 1, 2, 3, 4, obviously. I am also able to randomly order the players, like so:
activePlayersArray = [_players allKeys];
NSMutableArray *temp = [[NSMutableArray alloc] initWithArray:activePlayersArray];
int count = (int)[temp count];
for (int i = 0; i < count; ++i) {
int nElements = count - i;
int n = (arc4random() % nElements) + i;
[temp exchangeObjectAtIndex:i withObjectAtIndex:n];
}
activePlayersArray = [NSArray arrayWithArray:temp];
So how can I "combine" these two to get the results I want?
Hope you guys can help me.
Thanks!
This is really an algorithm problem, not an iOS problem. Here are the steps to follow
make a note of your randomly selected number
Sort the array in descending order as you normally would (as in Sort an NSArray in Descending Order)
Then split the array at the location of your special number (similar to How to split an NSArray into two equal pieces?)
after the split create a new array where the second piece now comes first
Another solution is to create a circular array of sorted elements and then traverse the array in reverse order.
I think this is what #Konsol intends, with a couple fixes: (1) it looks like the OP wants the order to be ascending, and (2) the array split in the other answer is at the midpoint. But I think the spirit is correct...
// Start with an unsorted (immutable?) input array of numbers (or any object
// that implements compare:.
// Pick a random location and produce an output array as described by the OP
NSMutableArray *mutableArray = [inputArray mutableCopy]; // if its not mutable already
[mutableArray sortUsingSelector:#selector(compare:)];
NSInteger inputIndex=arc4random_uniform(mutableArray.count);
NSArray *start = [mutableArray subarrayWithRange:NSMakeRange(inputIndex, mutableArray.count-inputIndex)];
NSArray *end = [mutableArray subarrayWithRange:NSMakeRange(0, inputIndex)];
NSArray *outputArray = [start arrayByAddingObjectsFromArray:end];
NSLog(#"%#", outputArray);
int count = (int)[activePlayersArray count];
int n = (arc4random() % nElements) + i;
NSMutableArray *temp = [[NSMutableArray alloc] init];
for (int i = 0; i < count; ++i) {
int nElements = count - i;
[temp addObject:[activePlayersArray objectAtIndex:(n-i)%count]];
}
activePlayersArray = [NSArray arrayWithArray:temp];
Hope it works!
I've definitely tried to do my due diligence on this one but keep coming up short. I have an array of objects that I have parsed and I want to iterate through these and store them. Assuming the array is 144 objects (just an example), I want to store it in groups of 12 to display in a tableview cell. Actually of those 12 objects in the array I'll likely only be displaying 3-4 in the cell, but all of those objects in the detail view.
To help explain what I mean (sorry if it hasn't made sense at this point) here's some of the code I've got that is getting the data.
NSMutableArray *objectsArray = [[NSMutableArray alloc] initWithCapacity:0];
for (TFHppleElement *element in objectsNode) {
PHSingleEvent *singleEvent = [[PHSingleEvent alloc]init];
[objectsArray addObject:singleEvent];
singleEvent.title = [[element firstChild] content];
}
This pulls down the entire array of objects (an unknown number but definitely a multiple of 12). How would I go about storing 12 objects at a time into a single event?
I can log the info with
PHSingleEvent *firstObject = [objectsArray objectAtIndex:0] // this one is null
PHSingleEvent *eventStartTime = [objectsArray objectAtIndex:1];
PHSingleEvent *eventEndTime = [objectsArray objectAtIndex:2];
...
PHSingleEvent *lastObject = [objectsArray objectAtIndex:11];
NSLog(#"single object of event: %#", eventStartTime.startTime);
NSLog(#"single object of event: %#", eventEndTime.endTime);
etc...
But the array keeps going past 12. I want to iterate up through each 12 objects and store those values, preferably as strings to be displayed in a cell and detail view.
Any ideas?
Thanks much in advance and I will be here to answer any questions if I was unclear.
C.
How about using a for loop? Assuming that each event object has 12 sub-objects (i.e. indices 0 - 11) you could achieve storing it by using a mod function. For example:
NSMutableArray *eventArray = [[NSMutableArray alloc] init];
for(int i=0; i<objectArray.count/12;i++){
int offset = 12*i;
NSMutableArray *event = [objectsArray subarrayWithRange:NSMakeRange(offset, 12)];
[eventArray addObject:event];
}
So now eventArray has n arrays, each of 12 objects (where n = totalObjects/12)
EDIT: A better idea would be to use NSDictionary. For example:
NSMutableArray *eventArray = [[NSMutableArray alloc] init];
for(int i=0; i<objectArray.count/12;i++){
int offset = 12*i;
NSDictionary *tempDict = [[NSDictionary alloc] initWithObjectsAndKeys: [objectsArray objectAtIndex: offset], #"eventStartTime", [objectsArray objectAtIndex: offset+1], #"eventEndTime", ..., [objectsArray objectAtIndex: offset+11, #"lastObject",nil];
[eventArray addObject:tempDict];
}
Then you can access each of the above objects using a similar statement as shown below:
PHSingleEvent *eventStartTime = [[eventArray objectAtIndex: index] objectForKey: #"eventStartTime"];
Hope this helps
This method will return an array of smaller arrays based on the group size you specify.
- (NSMutableArray*)makeGroupsOf:(int)groupSize fromArray:(NSArray*)array
{
if (!array || array.count == 0 || groupSize == 0)
{
return nil;
}
NSMutableArray *bigGroup = [[NSMutableArray alloc] init];
for (int i = 0; i < array.count; )
{
NSMutableArray *smallGroup = [[NSMutableArray alloc] initWithCapacity:groupSize];
for (int j = 0; j < groupSize && i < array.count; j++)
{
[smallGroup addObject:[array objectAtIndex:i]];
i++;
}
[bigGroup addObject:smallGroup];
}
return bigGroup;
}
I haven't tested it or anything though. After you have the big array with the smaller array(s) it is just a matter of filling each cell with any desired number of objects from the sub arrays.
Note: You might want to handle the cases when the array is empty, null or the group size is 0 differently.
How would I take an array with long list of numbers that contains duplicates, so for instance:
NSArray *array = [NSArray arrayWithObjects:#"45", #"60", #"100",#"100", #"100", #"60"nil];
Just imagine that this is a HUGE list of random numbers. Now I'm sure that I have to use something like NSSet for this, but i'm not sure how to execute this. Also, once we identify the duplicates I'm guessing that I would then add those numbers to an array, and then call
[array count];
Any ideas?
NSCountedSet *set = [[NSCountedSet alloc] initWithArray:array];
int duplicates = 0;
for (id object in set) {
if ([set countForObject:object] > 1) {
duplicates++;
}
}
This will calculate how many elements have a duplicate.
A sidenote, that array contains a bunch of strings, no numbers...
Anyway, if the goal is to get just the count you could use the following single line to get it.
NSUInteger diff = [array count] - [[array valueForKeyPath:#"#distinctUnionOfObjects.self"] count];
This uses KVC (Key-Value Coding) to get all distinct objects (that is ones without a dupe) counts them and gets the difference from the original count.
NSCountedSet is perfect for what you want to do.
NSArray *array = [NSArray arrayWithObjects:#"45", #"60", #"100",#"100", #"100", #"60",nil];
NSCountedSet *countedSet = [NSCountedSet setWithArray:array];
__block NSUInteger totalNumberOfDuplicates = 0;
[countedSet enumerateObjectsUsingBlock:^(id obj, BOOL *stop) {
NSUInteger duplicateCountForObject = [countedSet countForObject:obj];
if (duplicateCountForObject > 1)
totalNumberOfDuplicates += duplicateCountForObject;
NSLog(#"%# appears %ld times", obj, duplicateCountForObject);
}];
NSLog(#"Total number of duplicates is %ld", totalNumberOfDuplicates);
produces:
45 appears 1 times
60 appears 2 times
100 appears 3 times
Total number of duplicates is 5
Use filteredArrayUsingPredicate this use a predicate with your condition and return an array with the objects you need.
NSArray* arr=[[NSArray alloc] initWithObjects:#"10",#"11",#"10",#"2", nil];
NSLog(#"%d",[[arr filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"SELF == '2'"]] count]);
I have an array of arrays. The contained array's first elements are all NSDate objects. I would like to sort the array containing the arrays in order from most recent to least. For some reason, the below sorting algorithm results in an infinite loop. Can anyone help me out? Thank you.
Best...SL
//array is the array containing all of the other arrays(that have NSDates as their first elements)
//temp is the new array being added to the end of the array, to later be sorted into the correct position.
[array addObject:temp];
NSMutableArray *tempArray;
for (int i=0; i<[array count]; i++)
{
NSDate *session1, *session2;
session1 = [[array objectAtIndex:i] objectAtIndex:0];
session2 = [[array objectAtIndex:[array count]-1] objectAtIndex:0];
if([session1 compare:session2] == NSOrderedDescending)
{
tempArray = [array objectAtIndex:i];
[array insertObject:[array objectAtIndex:[array count]-1] atIndex:i];
[array insertObject:tempArray atIndex:[array count]-1];
}
}
This results in an infinite loop because, in every step, you're inserting two more values into the array. Thus your array is growing faster than you are traversing it. I'm assuming you meant to swap the values.
In any case, a much simpler and more efficient sort is to use the built-in sorting capabilities:
// NSArray *sortedArray, with the unsorted 'array' pulled from some other instance
sortedArray = [array sortedArrayUsingComparator:^(id a, id b) {
return [[b objectAtIndex:0] compare:[a objectAtIndex:0]];
}];
If array is mutable and you want to sort it in place:
[array sortUsingComparator:^(id a, id b) {
return [b[0] compare:a[0]];
}];
If array is immutable or you want to leave it alone and make a sorted copy:
NSArray *sortedArray = [array sortedArrayUsingComparator:^(id a, id b) {
return [b[0] compare:a[0]];
}];