Is there an efficient way to reorder NSMutableArray by changing its starting index? Example: if my array is [A,B,C,D,E], I would like to set 3rd element as starting element, and thus create the array [C,D,E,A,B].
I am doing it by slicing the array into two separate array, and then concatenating them. Is there a more efficient or clean way to do this?
Edit: the following is my current code
NSArray myArray = [self getMyArray]; // [A,B,C,D]
int startingIndex = 2;
NSArray *subArray1 = [myArray subarrayWithRange:NSMakeRange(_startingIndex, [myArray count] - _startingIndex + 1)]; // [C,D]
NSArray *subArray2 = [myArray subarrayWithRange:NSMakeRange(0, _startingIndex - 1)]; //[A,B]
NSMutableArray *reorderedArray = [NSMutableArray arrayWithArray:subArray1];
[reorderedArray addObjectsFromArray: subArray2]; //[C,D,A,B]
The most economical way of rotating NSMutableArray in terms of additional memory is the double-reversion algorithm described in this Q&A, because it does not require any additional storage. The idea is to reverse the entire array, and then reverse the two ranges separately.
In your example the array would be reversed, like this
E D C B A
then the first three elements would be reversed
C D E B A
and finally the tail of the array would be reversed:
C D E A B
Make a helper function for reversing a range, and call it three times:
reverseInPlace(myArray, 0, myArray.count-1);
reverseInPlace(myArray, 0, _startingIndex);
reverseInPlace(myArray, _startingIndex+1, myArray.count-1);
One way to implement reverseInPlace is as follows:
static void reverseInPlace(NSMutableArray *a, int f, int b) {
while (f < b) {
[a exchangeObjectAtIndex:f++ withObjectAtIndex:b--];
}
}
No, NSMutableArray is not documented to behave as a circular buffer (ring buffer), nor does it have operations you'd expect to have in one. Some potentially useful resources for solving this with a data structure where rotations have an O(1) cost:
Answer to a related Objective-C question about ring buffers, linking to CHDataStructures available also as a pod if you are so inclined.
Boost.Circular: a C++ circular buffer which you could wrap into some Objective-C++ for your purposes.
If all you need is to rotate a fixed, predictable length buffer, a circular buffer is a simple data structure to implement yourself. Apple's CoreAudio utility classes also include a general purpose ring buffer (CARingBuffer) you may find useful as a reference for your implementation.
If an in-place O(N) solution is sufficient for your needs, the other answer is a better choice than the varyingly complicated things I'm proposing above.
More efficient and cleaner:
NSRange range = NSMakeRange(0, startingIndex - 1);
NSArray *subArray = [array subarrayWithRange:range];
[array removeObjectsInRange:range];
[array addObjectsFromArray:subArray];
Related
I recently discovering these classes like NSMapTable and NSPointerArray, which work like the traditional collections, but also let you store weak references or plain old C pointers. Unfortunately it looks like you can't use the for...in syntax to iterate over non-NSObject pointers. For example:
typedef struct Segment {
CGPoint bottom, top;
} Segment;
...
NSPointerArray *segments = [[NSPointerArray alloc]
initWithOptions:NSPointerFunctionsOpaqueMemory];
...
Segment *s = malloc(sizeof(Segment));
[segments addPointer: s];
...
for (Segment *s in segments) { // nope...
The compiler does not like that last line. The error:
Selector element type 'Segment *' (aka 'struct Segment *') is not a valid object
So, do I need to do this?
for (int i=0, len=segments.count; i<len; i++) {
Segment *seg = [segments pointerAtIndex:i];
...
That's not the end of the world, but I just want to make sure.
(This might be more of theoretical interest.)
NSPointerArray does conform to the NSFastEnumeration protocol, it is only the
for (id object in collection) language construct that cannot be used with arbitrary pointers which
are not Objective-C pointers.
But you can get a whole bunch of pointers from the array by calling the NSFastEnumeration
method countByEnumeratingWithState:objects:count: directly. This is a bit tricky because
that method need not fill the supplied buffer (as explained here: How for in loop works internally - Objective C - Foundation).
Here is a simple example how this would work:
__unsafe_unretained id objs[10];
NSUInteger count = [segments countByEnumeratingWithState:&state
objects:objs count:10];
// Now state.itemsPtr points to an array of pointers:
for (NSUInteger i = 0; i < count; i++) {
Segment *s = (__bridge Segment *)state.itemsPtr[i];
NSLog(#"%p", s);
}
So this does not help to make the code simpler and you probably want to stick with
your explicit loop.
But for large arrays it might improve the performance because the pointers are "fetched"
in batches from the array instead of each pointer separately.
the for (... in ...) syntax won't work in this case because Segment is a struct, not an Objective C object. Your second for loop should work.
I intend to make a program that does the following:
Create an NSArray populated with numbers from 1 to 100,000.
Loop over some code that deletes certain elements of the NSArray when certain conditions are met.
Store the resultant NSArray.
However the above steps will also be looped over many times and so I need a fast way of making this NSArray that has 100,000 number elements.
So what is the fastest way of doing it?
Is there an alternative to iteratively populating an Array using a for loop? Such as an NSArray method that could do this quickly for me?
Or perhaps I could make the NSArray with the 100,000 numbers by any means the first time. And then create every new NSArray (for step 1) by using method arraywithArray? (is it quicker way of doing it?)
Or perhaps you have something completely different in mind that will achieve what I want.
edit: replace NSArray with NSMutableArray in above post
It is difficult to tell in advance which method will be the fastest. I like the block based functions, e.g.
NSMutableArray *array = ...; // your mutable array
NSIndexSet *toBeRemoved = [array indexesOfObjectsPassingTest:^BOOL(NSNumber *num, NSUInteger idx, BOOL *stop) {
// Block is called for each number "num" in the array.
// return YES if the element should be removed and NO otherwise;
}];
[array removeObjectsAtIndexes:toBeRemoved];
You should probably start with a correctly working algorithm and then use Instruments for profiling.
You may want to look at NSMutableIndexSet. It is designed to efficiently store ranges of numbers.
You can initialize it like this:
NSMutableIndexSet *set = [[NSMutableIndexSet alloc]
initWithIndexesInRange:NSMakeRange(1, 100000)];
Then you can remove, for example, 123 from it like this:
[set removeIndex:123];
Or you can remove 400 through 409 like this:
[set removeIndexesInRange:NSMakeRange(400, 10)];
You can iterate through all of the remaining indexes in the set like this:
[set enumerateIndexesUsingBlock:^(NSUInteger i, BOOL *stop) {
NSLog(#"set still includes %lu", (unsigned long)i);
}];
or, more efficiently, like this:
[set enumerateRangesUsingBlock:^(NSRange range, BOOL *stop) {
NSLog(#"set still includes %lu indexes starting at %lu",
(unsigned long)range.length, (unsigned long)range.location);
}];
I'm quite certain it will be fastest to create the array using a c array, then creating an NSArray from that (benchmark coming soon). Depending on how you want to delete the numbers, it may be fastest to do that in the initial loop:
const int max_num = 100000;
...
id *nums = malloc(max_num * sizeof(*nums));
int c = 0;
for(int i = 1; i <= max_num; i++) {
if(!should_skip(i)) nums[c++] = #(i);
}
NSArray *nsa = [NSArray arrayWithObjects:nums count:c];
First benchmark was somewhat surprising. For 100M objects:
NSArray alloc init: 8.6s
NSArray alloc initWithCapacity: 8.6s
id *nums: 6.4s
So an array is faster, but not by as much as I expected.
You can use fast enumeration to search through the array.
for(NSNumber item in myArrayOfNumbers)
{
If(some condition)
{
NSLog(#"Found an Item: %#",item);
}
}
You might want to reconsider what you are doing here. Ask yourself why you want such an array. If your goal is to manipulate an arbitrarily large collection of integers, you'll likely prefer to use NSIndexSet (and its mutable counterpart).
If you really want to manipulate a NSArray in the most efficient way, you will want to implement a dedicated subclass that is especially optimized for this kind of job.
I've got some code to convert a large (many gigabytes) XML file into another format.
Among other things, I need to store one or two gigabytes of floats in a hash table (two floats for each entry), with an int as the value's key.
Currently, I'm using NSMutableDictionary and a custom class containing the two floats:
// create the dictionary
NSMutableDictionary *points = [[NSMutableDictionary alloc] init];
// add an entry (the data is read from an XML file using libxml)
int pointId = 213453;
float x = 42.313554;
float y = -21.135213;
MyPoint *point = [[MyPoint alloc] initWithX:x Y:y];
[points setObject:point forKey:[NSNumber numberWithInt:pointId]];
[point release];
// retrieve an entry (this happens later on while parsing the same XML file)
int pointId = 213453;
float x;
float y;
MyPoint *point = [points objectForKey:[NSNumber numberWithInt:pointId]];
x = point.x;
y = point.y;
This data set is consuming about 800MB of RAM with the XML file I'm working with now, and it takes quite a long time to execute. I'd like to have better performance, but even more important I need to get the memory consumption down so I can process even larger XML files.
objc_msg_send is right up there in a profile of the code, as is - [NSNumber numberWithInt:], and I'm sure I can get the memory usage down by avoiding objects altogether, but I don't know much about C programming (this project is certainly teaching me!).
How can I replace NSMuableDictionary, NSNumber MyPoint with an efficient C data structure? Without any third party library dependencies?
I'd also like to be able to write this data structure to files on the disk, so I can work with a dataset that doesn't entirely fit into memory, but I can probably live without this capability.
(for those not familiar with Objective-C, the NSMutableDictionary class can only store Obj-C objects, and it the keys must also be objects. NSNumber and MyPoint are dumb container classes to allow NSMutableDictionary to work with float and int values.)
EDIT:
I've tried using CFMutableDictionary to store structs, as per apple's sample code. When the dictionary is empty, it performs great. But as the dictionary grows it gets slower and slower. About 25% through parsing a file (~4 million items in the dictionary) it starts to chug, two orders of magnitude slower than earlier in the file.
NSMutableDictionary doesn't have the same performance issue. Instruments shows a lot of activity applying hashes and comparing the keys of the dictionary (the intEqual() method below). Comparing an int is fast, so something is very wrong for it to be executing so often.
Here's my code to create the dictionary:
typedef struct {
float lat;
float lon;
} AGPrimitiveCoord;
void agPrimitveCoordRelease(CFAllocatorRef allocator, const void *ptr) {
CFAllocatorDeallocate(allocator, (AGPrimitiveCoord *)ptr);
}
Boolean agPrimitveCoordEqual(const void *ptr1, const void *ptr2) {
AGPrimitiveCoord *p1 = (AGPrimitiveCoord *)ptr1;
AGPrimitiveCoord *p2 = (AGPrimitiveCoord *)ptr2;
return (fabsf(p1->lat - p2->lat) < 0.0000001 && fabsf(p1->lon - p2->lon) < 0.0000001);
}
Boolean intEqual(const void *ptr1, const void *ptr2) {
return (int)ptr1 == (int)ptr2;
}
CFHashCode intHash(const void *ptr) {
return (CFHashCode)((int)ptr);
}
// init storage dictionary
CFDictionaryKeyCallBacks intKeyCallBacks = {0, NULL, NULL, NULL, intEqual, intHash};
CFDictionaryValueCallBacks agPrimitveCoordValueCallBacks = {0, NULL /*agPrimitveCoordRetain*/, agPrimitveCoordRelease, NULL, agPrimitveCoordEqual};
temporaryNodeStore = CFDictionaryCreateMutable(NULL, 0, &intKeyCallBacks, &agPrimitveCoordValueCallBacks);
// add an item to the dictionary
- (void)parserRecordNode:(int)nodeId lat:(float)lat lon:(float)lon
{
AGPrimitiveCoord *coordPtr = (AGPrimitiveCoord *)CFAllocatorAllocate(NULL, sizeof(AGPrimitiveCoord), 0);
coordPtr->lat = lat;
coordPtr->lon = lon;
CFDictionarySetValue(temporaryNodeStore, (void *)nodeId, coordPtr);
}
EDIT 2:
The performance problem was due to the almost useless hashing implementation in Apple's sample code. I got the performance way up by using this:
// hash algorithm from http://burtleburtle.net/bob/hash/integer.html
uint32_t a = abs((int)ptr);
a = (a+0x7ed55d16) + (a<<12);
a = (a^0xc761c23c) ^ (a>>19);
a = (a+0x165667b1) + (a<<5);
a = (a+0xd3a2646c) ^ (a<<9);
a = (a+0xfd7046c5) + (a<<3);
a = (a^0xb55a4f09) ^ (a>>16);
If you want NSMutableDictionary-like behavior but with malloc'd memory, you can drop down to CFDictionary (or in your case, CFMutableDictionary). It's actually the underpinnings of NSMutableDictionary, but it allows some customization, namely you can tell it that you're not storing objects. When you call CFDictionaryCreateMutable() you give it a struct that describes what sort of values you're handing it (it contains pointers that tell it how to retain, release, describe, hash, and compare your values). So if you want to use a struct containing two floats, and you're happy using malloc'd memory for each struct, you can malloc your struct, populate it, and hand that to the CFDictionary, and then you can write the callback functions such that they work with your particular struct. The only restriction on the keys and objects you can use CFDictionary with is they need to fit inside a void *.
For this sort of thing I would just use C++ containers std::unordered_map and std::pair. You can use them in Objective-C++. Just give your files a .mm extension instead of the usual .m extension.
Update
In your comment you said you've never done C++ before. In that case, you should either try Kevin Ballard's answer of CFDictionary, or check out the hcreate, hdestroy, and hsearch functions in the standard library.
hcreate man page
Rename your .m file to .mm and switch to using C++:
std::map<int, std::pair<float>> points;
I have an NSArray arr. It has a bunch of NSNumber objects. I'm trying to calculate statistics analysis on the array using GNU's GSL. GSL takes parameters as C-style arrays.
Is there any mechanism that can, for example, run 'intValue' on all of the objects in a NSArray object, and convert the results that to a C-style array?
I don't really want to copy the contents of the NSArray to a C-style array, as it's a waste of space and cycles, so I'm looking for an alternative.
The mechanism you're describing — run intValue on all the objects in the NSArray and give a C-style array — seems to be exactly the same thing you describe as "a waste of space and cycles." It's also the only real way to do this if you need a C-style array of ints. Best approach I can think of:
int *c_array = malloc(sizeof(int) * [yourArray count]);
[yourArray enumerateObjectsWithOptions:NSEnumerationConcurrent
usingBlock:^(id number, NSUInteger index, BOOL *unused) {
c_array[index] = [number intValue];
}];
Try this:
id *numArray = calloc(sizeof(id), yourArray.count);
[yourArray getObjects: numArray range: NSMakeRange(0, yourArray.count)];
That gives you a C-array of NSNumbers. An alternative that gives you ints:
int *numArray = calloc(sizeof(int), yourArray.count);
for (int i = 0; i< yourArray.count; i++)
numArray[i] = [[yourArray objectAtIndex: i] intValue];
There is no way to tell yourArray to return a C-array of ints directly. NSArray has no concept of the contents it has, except that they are ids, and must be retained and released at the right times. It can at most return a C-array of ids, as in my first example.
You could probably write your own simple array class that contains ints (or floats or doubles, etc.) directly, in an internal C array, but there is no stock class for this.
I have cpp code where the struct objects are put into the CLISTS. I am porting this code into Objective C.
CLIST is similar to a doubly linked list with .RemoveAt , .GetAt , .InsertBefore , .GetNext , .GetHeadPosition functions.
How to implement the same in Objective C.
Do I need to implement doubly linked list in Objective C.Is there any other predefined methods to use it.
A CLIST is presumably circular? Hence the GetHeadPosition?
In any case, NSArray (or, NSMutableArray in this case, since you want to be inserting) is the normal way to keep ordered lists in Objective-C.
For RemoveAt, use removeObjectAtIndex:. For GetAt, use objectAtIndex:. For InsertBefore you're probably going to want to write a little something like:
- (void)insert:(id)objectToInsert before:(id)referenceObject
{
int index = [array indexOfObject:referenceObject];
if(index == NSNotFound) return; // or whatever you'd expect.
// Maybe object is just inserted at the end?
index = index - 1;
if(index < 0) index = [array count];
[array insertObject:objectToInsert atIndex:index];
}
(which would probably go better in an NSArray category, but you get the point)
For GetNext and GetHeadPosition you probably want to keep your array position in a separate variable. So for GetNext:
arrayPosition = (arrayPosition + 1)%[array count];
return [array objectAtIndex:arrayPosition];
And for GetHeadPosition, just:
return arrayPosition;
EDIT: for iterating through an NSArray, the easiest way is actually to ignore anything explicit and just use:
for(ObjectType *object in array)
{
/* do something with object */
}
That generally means you don't really need an analogue of GetNext, but you can't mutate the array while in that loop so it's not always usable.