Travel through NSArray without using loop but cursors? - ios

I have an NSArray with objects inside (CLLocation). I can have 50, 100, 300 or more objects inside. In fact, this array is used while the user walking and can follow a direction. But the user can start at the middle of my NSArray, you know what I mean ?
Well, I Have to loop all the time my array to know where my user is compare to the locations in my array.
My question is: Is it possible to use a thing like in Java with a "cursor" in a list, and simply call "Next object" to travel in my array instead of loop ?
Because I need that the user walk on all location of my array.
Example:
Count of my array: 100
User start at location at index 34 (the nearest location found)
The user must do 35, 36, 37... 100 AND 0,1,2,3 ... until 33.
Hope it's clear, I really don't know how to do this without using for loop...
Thank you for help and suggestions!
Regards,
Lapinou.

Here's one way:
NSArray * arr = ... yourArray
int index = [arr indexOfObject:currentLocation];
index ++;
if (index == arr.count) index = 0;
id nextLocation = arr[index];
Another might be to create a global counter variable that stores the current position. If these needs to last after the user closes the app, you could write it to user defaults

Is looks like you are want to use NSEnumerator
NSEnumerator Class Reference
NSArray *anArray = // ... ;
NSEnumerator *enumerator = [anArray objectEnumerator];
id object;
while ((object = [enumerator nextObject])) {
// do something with object...
}

try this:
#interface ArrayEnumerator : NSEnumerator
{
NSArray* array;
NSInteger index;
NSInteger startIndex;
BOOL over;
}
- (id)initWithArray:(NSArray*)anArray
atIndex:(NSInteger)anIndex;
#end
#implementation ArrayEnumerator
- (id)initWithArray:(NSArray*)anArray
atIndex:(NSInteger)anIndex
{
if (self=[super init]) {
array = anArray;
index = anIndex;
startIndex = anIndex;
over = NO;
}
return self;
}
- (id)nextObject
{
if (index == [array count]) {
index = 0;
over = YES;
}
if (over && index == startIndex)
return nil;
return array[index++];
}
- (NSArray*)allObjects
{
return array;
}
#end
#implementation ViewController
- (void)viewDidLoad
{
NSArray* array = #[#0,#1,#2,#3,#4,#5,#6,#7,#8,#9];
id element;
ArrayEnumerator* enumerator = [[ArrayEnumerator alloc] initWithArray:array atIndex:4];
while (element = [enumerator nextObject])
NSLog(#"%#", element);
}
#end

What is wrong with a for loop?
An iterator is typically used on lists, because you can't access elements in a list by index. However you are working with an array, so you don't need an iterator, but rather some clever way of accessing the array in the desired order.
Maybe this code can provide you with some ideas. This will run from 34 to 100, then start with 0 and go up to 33.
for (int i = 34; i < 134; i++)
{
int ix = i % 100;
id whatever = arr[ix];
}

You can access array elements by index:
CLLocation * myLocation = myArray[34];
(or)
int i = 34;
CLLocation * myLocation = myArray[i];

Related

NSNumber in arrays, ios

I am trying to learn about how to put numbers into an array with nsnumber. The exact thing I'm stuck with is, To build the sequence in the array, we're going to need a loop. Between creating the sequence array and returning it, declare a for loop whose counter is limited by index + 1 and increments by one.
Since the sequence requires the two previous numbers to calculate the next one, we need to prime the sequence. We're going to need to manually pass in #0 and #1 on the first two iterations of the loop. This is what I have so far.
(NSArray *)arrayWithFibonacciSequenceToIndex:(NSUInteger)index
{
NSMutableArray *sequence = [NSMutableArray array];
for(NSUInteger i = 0; i < 1; i++)
{
index = i+1;
}
return sequence;
}
Am I on the right track? I'm not sure if my for loop is correct. Do I put sequence into the for loop and add the nsnumber #0 and #1 there or do I put those numbers into the sequence outside the loop?
To insert a number in an NSArray, you have to wrap them in a NSNumber:
NSInteger a = 5;
NSNumber number = #(a); // ou #5;
to perform mathematical operations on 2 NSNumbers, you have to convert them to integer (or double, float...) before
NSNumber * number1 = #1;
NSNumber * number2 = #6;
NSInteger sum = [number1 integerValue] + [number2 integerValue];
for the fib problem, youre loop is correct. The way I would think of this is : I add my value in the for loop, and if I'm adding the 1st or 2nd element, then I put a 0, else I sum the last 2 elements:
- (NSArray *) fibbonacciSequenceWithSize:(NSInteger)size
{
NSMutableArray * result = [NSMutableArray new];
for(NSInteger idx = 0; i < size ; i ++)
{
// first 2 numbers of fib sequence are 1
if(idx == 0 || idx == 1)
{
[result addObject:#1];
}
else
{
// Add the 2 previous number
// F2 = F1 + F0
NSinteger next = [result[idx - 2] integerValue] + [result[idx - 1] integerValue];
[result addObject:#(next)];
}
}
return [result copy]; // copy the NSMutableArray in a NSArray
}
You can clean up the code by having a Fibonacci function that provides the sum of the last two elements.
- (NSNumber *)nextFibInArray:(NSArray *)array {
if (array.count < 2) return #1;
NSInteger lastIndex = array.count - 1;
return #([array[lastIndex-1] intValue] + [array[lastIndex] intValue]);
}
Then the loop is cleaner, too.
- (NSArray *)fibonacciWithLength:(NSInteger)length {
NSMutableArray *result = [#[] mutableCopy];
for (NSInteger i=0; i<length; i++) {
[result addObject:[self nextFibInArray:result]];
}
return result;
}
We could trim some execution time fat from this, but for short enough sequences, this should be clear and quick enough.

Return the first number which occurs only once in an NSArray

I would like to know what's the best or most appropriate approach for this question: Given a list of numbers example [2, 3, 4, 2, 3], return the first number that occurs only once in the list.
I have followed some algorithms approach and came up with this, but not sure if there are any built-in helper functions in Objective-C that will allow me to do this with a better performance..
If there are not built-ins solutions, is there is any improvements that can be made to my approach or any other solution that could be better in terms of performance?
This is my updated solution for this:
For testing:
#import "NSArray+Addons.h"
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
NSArray<NSNumber *> *array = #[#(2), #(7), #(3), #(2), #(3), #(2), #(7), #(3), #(2), #(3), #(4), #(7), #(5), #(5), #(9)];
NSLog(#"Unique number: %#", [array firstUniqueNumber]);
}
#end
NSArray category:
#import "NSArray+Addons.h"
#import "NSMutableDictionary+Addons.h"
#implementation NSArray (Addons)
- (NSNumber *)firstUniqueNumber
{
if (!self.count)
{
return nil;
}
NSMutableDictionary<NSNumber *, NSNumber *> *myUniqueNumbers = [[NSMutableDictionary alloc] init];
return [myUniqueNumbers uniqueValueFromArray:self];
}
#end
NSMutableDictionary category:
#import "NSMutableDictionary+Addons.h"
#implementation NSMutableDictionary (Addons)
- (NSNumber *)uniqueValueFromArray:(NSArray<NSNumber *> *)array
{
if (!array.count)
{
return nil;
}
for (NSNumber *number in array)
{
if (!self[number])
{
self[number] = [NSNumber numberWithInteger:1];
}
else
{
NSInteger count = [self[number] integerValue];
count++;
self[number] = [NSNumber numberWithInteger:count];
}
}
return [self uniqueNumberWithArray:array];
}
- (NSNumber *)uniqueNumberWithArray:(NSArray<NSNumber *> *)array
{
if (!array.count)
{
return nil;
}
NSNumber *uniqueNumber = nil;
for (NSInteger index = array.count - 1; index > 0; index--)
{
NSNumber *key = array[index];
if (self[key] && [self[key] integerValue] == 1)
{
uniqueNumber = key;
}
}
return uniqueNumber;
}
#end
NSCountedSet* set = [[NSCountedSet alloc] initWithArray:array];
NSUInteger index = [array indexOfObjectPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop){
return [set countForObject:obj] == 1;
}];
return index == NSNotFound ? nil : [array objectAtIndex:index];
This problem can be reduced to element distinctness problem, so there is no linear time solution, without using hashing and extra space.
One simple solution in O(n) time on average + space is:
Build a hash based histogram of the data, that maps each value to the number of its occurances.
Find the first number in the array that its value in the histogram is 1.
Pseudo code:
map = new hashmap
for each element x:
if map contains x is a key:
map.put(x,map.get(x)+1)
else:
map.put(x,1)
for each element x in array:
if map.get(x) == 1:
return x
//if reached here - no distinct element
Example:
array = [2, 3, 4, 2, 3]
create histogram: {[2=2] [3=2], [4=1]}
iterate the array:
check 2, it has value of 2 in histogram. continue
check 3, it has value of 2 in histogram. continue
check 4, it has value of 1 in histogram. Return it and finish.
-(NSNumber *)returnFirstUniqueFromArray: (NSArray *)array{
//put the numbers in a set
NSCountedSet *numbers = [[NSCountedSet alloc] initWithArray:array];
for(NSNumber *number in array){
//if it only occurs once return
if([numbers countForObject:number]==1) return number;
}
return nil;
}
They key being here you need a good way to keep track of how many times something occurs so take advantage of NSCountedSet's "count" method. Will tell you how many times an object occurs.

iOS App crashes at end of for loop

I'm pretty new to Objective C, and I've been having quite the roadblock in my code...
I am making a (very) simple card game to run on iOS. All you are supposed to do is draw cards until a Joker is drawn, then the game ends.
My app has been crashing at a curly bracket at the end of a for loop that is making card objects to put into the array
Here's my Deck.m:
#import "Deck.h"
#import "Card.h"
#implementation Deck
#synthesize deckArray;
- (void)removeCard {
[deckArray removeObjectAtIndex:deckArray.count];
}
- (void)generate {
NSLog(#"Generating deck...");
NSMutableArray *deckArray = [[NSMutableArray alloc]init];
for (int i = 0; i < 14; i++) {
//Make a card
Card *card = [[Card alloc]init];
//Give it some values
card.value = i + 1;
card.suit = #"Hearts";
//Put card in array
[deckArray addObject:card];
NSLog(#"Added object (%#) to array",card);
}
for (int i = 0; i < 14; i++) {
//Make a card
Card *card = [[Card alloc]init];
//Give it some values
card.value = i + 1;
card.suit = #"Spades";
//Put card in array
[deckArray addObject:card];
NSLog(#"Added object (%#) to array",card);
}
for (int i = 0; i < 14; i++) {
//Make a card
Card *card = [[Card alloc]init];
//Give it some values
card.value = i + 1;
card.suit = #"Diamonds";
//Put card in array
[deckArray addObject:card];
NSLog(#"Added object (%#) to array",card);
}
for (int i = 0; i < 14; i++) {
//Make a card
Card *card = [[Card alloc]init];
//Give it some values
card.value = i + 1;
card.suit = #"Clubs";
//Put card in array
[deckArray addObject:card];
NSLog(#"Added object (%#) to array",card);
} //Crashes on this line: Thread 1: Breakpoint 2.1
NSLog(#"Generated deck");
}
- (Card *)topCard {
return [deckArray objectAtIndex:deckArray.count];
}
#end
I'm pretty sure it is the most obvious thing in the world but, again, I am pretty new on programming in general
Thank you in advance!
I can see issue in tow methods: removeCard and topCard.
You try access object which is out of bounds:
[deckArray objectAtIndex:deckArray.count]
If you have 5 items in the array deckArray.count returns 5 but last index is 4 (arrays index are zero based) so you have to replace call to deckArray.count to deckArray.count-1.
- (Card *)topCard {
return [deckArray objectAtIndex:deckArray.count-1];
}
And do the same in removeCard method.
This line : NSMutableArray *deckArray = [[NSMutableArray alloc]init];
You already declared deckArray in your header file(.h).
You should do: deckArray = [[NSMutableArray alloc] init];
As told in the Crash log, I had my 'remove card' method take away an object that didn't exist because arrays are zero-based. Also, I put self. in front of deckArray seemed to help. I should've learned a bit more Obj-C before posting this question, so my apologies to you. .count - 1 also helped on the other methods.

How to remove value from NSMutableArray

I have a NSMutableArray "coordinates" which gives me values like this
2014-01-11 09:52:15.479 DreamCloud[397:70b] (
{
1000 = {
Linecolor = 0X6495ED;
Lines = "4-s";
Xcord = "77.000000";
Xposition = "54.500000";
Ycord = "111.500000";
Yposition = "51.500000";
};
},
{
1001 = {
Linecolor = 0X6495ED;
Lines = "4-s";
Xcord = "45.000000";
Xposition = "42.500000";
Ycord = "417.000000";
Yposition = "54.000000";
};
},
{
1000 = {
Linecolor = 0X6495ED;
Lines = "4-s";
Xcord = "73.000000";
Xposition = "50.500000";
Ycord = "111.000000";
Yposition = "51.000000";
};
}
)
Within this I need ti remove the values for 1001 and recreate the array without 1001 . How do I do this.I am new in ios so I did not figure out how to do this .
for (NSMutableDictionary *deltag in deletelinearray)
{
NSMutableDictionary *gettagsdeleted = [deltag objectForKey:[NSString stringWithFormat:#"%d",myV.tag]];
NSLog(#"%#",gettagsdeleted);
int starttag=[gettagsdeleted objectForKey:#"Starttag"];
int endtag=[gettagsdeleted objectForKey:#"Endtag"];
}
NSLog(#"%#",coordinates);
Above is the code where in "coordinates " I get the array and start-tags and end-tags are 1000, 1001 . In coordinates I don't know the index as Kumar Kl said .
Consider your array name is coorditates
for (NSDictionary *dict in coorditates) {
if ([dict objectForKey:[NSString stringWithFormat:#"%d",1001]]) {
[coorditates removeObject:dict];
break;
}
}
You can also use NSPredicate but, for that coorditates array must be NSMutableArray
NSPredicate *pred = [NSPredicate predicateWithFormat:#"ANY self.#allKeys != %#", #"1001"];
[coorditates filterUsingPredicate:pred];
Try this for loop instead. Instead of selecting the object with the key it removes it.
for (NSMutableDictionary *deltag in deletelinearray)
{
[coordinates removeObjectForKey:[NSString stringWithFormat:#"%d",myV.tag]];
}
It is not a good coding practice to modify(insert or delete) the items in array while enumerating it. So first find your index and then delete it.
You don't need to create a new array, once the details with "1001" is removed. You already have an update array.
NSString *deleteKey=#"1001";
__block int deleteIndex=-1;
[arr enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
for (NSString *key in [obj allKeys]) {
if([key isEqualToString:deleteKey]){
deleteIndex=idx;
*stop=YES;
}
}
}];
if(deleteIndex>=0){
[arr removeObjectAtIndex:deleteIndex];
}
You want to call the removeObjectAtIndex: function, but it appears your array contains dictionary objects and you want to remove the one with the key 1001. What you want to avoid is removing the object WHILE looping through the array.
So, what I would do is create a variable that will hold the index of the item once you find it, then loop through the array and once you find the object that it matches store the index and break. After, you shouldn't need to recreate the array after you remove the item, removing the object at the index you provide the above function will do just that for you. In your case, you'll want to do the following:
NSString *key = #"1001";
for (NSInteger index = 0; index < array.count; index++) {
NSDictionary *dictionary = coordinates[index];
if (dictionary[key]) {
indexToDelete = index;
break;
}
}
[coordinates removeObjectAtIndex:1001];
int i = 0;
for (NSDictionary *dict in coorditates)
{
if ([dict objectForKey:#"1001"])
{
[coorditates removeObjectAtIndex:i];
}
i++;
}

Insert an object into NSMutable array and shift element one position ahead iOS

I want to insert an object (say 1.5) into NSMutableArray (say array with content: 1,2,3,4) between 1 and 2. The resultant array would be one element greater (say 1,1.5,2,3,4).
How can this be acheived in iOS using NSMutableArray?
Assuming you know the index to insert at, just use NSMutableArray's insertObject:atIndex: (reference). In your case, you want:
[yourMutableArray insertObject:#(1.5) atIndex:1];
If you don't know the index, you can do something like this (copy-pasted because nobody likes broken links):
#implementation NSMutableArray (SelfSorting)
- (void)insertNumberAtSortedLocation:(NSNumber *)aNumber
{
NSUInteger count = [self count];
// if there are no contents yet, simply add it
if (!count)
{
[self addObject:aNumber];
return;
}
NSRange searchRange;
searchRange.location = 0;
searchRange.length = count;
// bubble sort finding of insert point
do
{
NSInteger index = searchRange.location + searchRange.length/2;
NSNumber *testNumber = [self objectAtIndex:index];
switch ([aNumber compare:testNumber])
{
case NSOrderedAscending:
{
//searchRange.length = searchRange.length / 2;
searchRange.length = index - searchRange.location;
break;
}
case NSOrderedDescending:
{
int oldLocation = searchRange.location;
searchRange.location = index+1;
searchRange.length = searchRange.length - (searchRange.location - oldLocation);
break;
}
case NSOrderedSame:
{
searchRange.length = 0;
searchRange.location = index;
break;
}
}
} while (searchRange.length>0);
// insert at found point
[self insertObject:aNumber atIndex:searchRange.location];
}
And then, call:
[yourMutableArray insertNumberAtSortedLocation:#(1.5)];
Two lines of code
Just append the item and then sort or sort at usage time, sorting is actually very cheap, almost O(n) for non pathological cases.
NSMutableArray *a = [#[#1, #2 ,#3 ,#4] mutableCopy];
// Two lines of code:
[a addObject:#(1.5)];
[a sortUsingSelector:#selector(compare:)];
NSLog(#"a: %#", a);
NSLog oputput:
a: (
1,
"1.5",
2,
3,
4
)
The above should be O(log n)
Or if you don't want the entire array sorted, just insert after the first entry that is less than it:
NSUInteger count = [a count];
int index = 0;
while (index < count && [a[index] compare:aNumber] == NSOrderedAscending) {
index += 1;
}
[a insertObject:aNumber atIndex:index];
The above is O(n) as opposed to a binary search which is O(log n) but for most arrays there is not a meaningful time difference.
For the example in your question, you would write [array insertObject:#(1.5) atIndex:1]
NSMutableArray * foo = [[NSMutableArray alloc] init];
[foo insertObject:<#(id)#> atIndex:<#(NSUInteger)#>]

Resources