Deleting Set of Indexs from NSMutableArray Efficiently - objective-c

i have a set of Index setOFIndex = {0,1,3,4}.
now i want to remove this set of index from an NSMutableArray ?
what is the efficient method to do that ?
i have checked for any library method , but not able to find any.
i cant use removeObjectAtIndex directly as at each deletion array will be shifted by one.

NSMutableArray *array = [NSMutableArray arrayWithObjects: #"one", #"a", #"two", #"b", #"three", #"four", nil];
NSMutableIndexSet *indexes = [NSMutableIndexSet indexSetWithIndex:1];
[indexes addIndex:3];
[array removeObjectsAtIndexes:indexes];
NSLog(#"array: %#", array);
// Output: array: (one, two, three, four)
read the documentation

You should use NSMUTABleArray's method removeObjectsAtIndexes:
This is the code from documentation
NSMutableArray *array = [NSMutableArray arrayWithObjects: #"one", #"a", #"two", #"b", #"three", #"four", nil];
NSMutableIndexSet *indexes = [NSMutableIndexSet indexSetWithIndex:1];
[indexes addIndex:3];
[array removeObjectsAtIndexes:indexes];
NSLog(#"array: %#", array);
I simply don't understand why people don't read documentation.

Why don't you use
– removeObjectsInArray:
Convert your Indexset to array and then use above method.
EDIT:
Very straight forward example from documentation.
NSMutableArray *array = [NSMutableArray arrayWithObjects: #"one", #"a", #"two", #"b", #"three", #"four", nil];
NSMutableIndexSet *indexes = [NSMutableIndexSet indexSetWithIndex:1];
[indexes addIndex:3];
[array removeObjectsAtIndexes:indexes];
NSLog(#"array: %#", array);

Related

Replacing an element in a NSMutableArray that is multi dimensional?

I need to be able to replace an object in a multi dimensional NSMutableArray (nested actually) of strings.
I know for a single dimensional array you would do this:
[arrayOfTiles replaceObjectAtIndex:4 withObject:#"w"];
But not sure how to do this for a multi dimensional array (in this case a nested array).
Here is the array I have setup.
NSMutableArray *arrayOfTiles = [[NSMutableArray alloc] initWithCapacity: 5];
[arrayOfTiles insertObject: [NSArray arrayWithObjects: #"a", #"b", #"c", #"d",
#"e", nil] atIndex: 0];
[arrayOfTiles insertObject: [NSArray arrayWithObjects: #"f", #"g", #"h", #"i",
#"j", nil] atIndex: 1];
How would I accomplish a simple replacement of say (for example) the letter "i" to change it to letter "w" at runtime?
You need to make inner array mutable first
NSMutableArray *arrayOfTiles = [[NSMutableArray alloc] initWithCapacity: 5];
[arrayOfTiles insertObject: [NSMutableArray arrayWithObjects: #"a", #"b", #"c", #"d",
#"e", nil] atIndex: 0];
[arrayOfTiles insertObject: [NSMutableArray arrayWithObjects: #"f", #"g", #"h", #"i",
#"j", nil] atIndex: 1];
then you can do this
arrayOfTiles[1][3] = #"w";
Using modern notation, you can treat nested NSArrays just like multi-dimensional C arrays
arrayOfTiles[1][3] = #"w";

How to count the mutable array objects in iphone?

I am fresher to iOS. In my application i have 3 mutable arrays with objects like
NSMutableArray *MuteItem = [NSMutableArray alloc]initWithObjects:#"a", #"b", #"b", #"c", #"c", #"c", nil]];
NSMutableArray *MuteQuantity = [NSMutableArray alloc]initWithObjects:#"1", #"1", #"1", #"1", #"1", #"1", nil]];
NSMutableArray *MutePrice = [NSMutableArray alloc]initWithObjects:#"4", #"3", #"3", #"6", #"6", #"6", nil]];
Now i need to print that 3 mutable arrays values with counting the same item's quantity and calculate the price also like objects
MuteItem = { a, b, c }
MuteQuantity = { 1, 2, 3 } // counting of same item's quantity like {1, 1+1, 1+1+1}
MutePrice = { 4, 6, 18 } // here addition of same item's prices like {4, 3+3, 6+6+6}
So anybody, would you please help me in this problem. Thanks in advance.
This code will do exactly as you requested, and will even handle any keys in MuteItem, and will generate three new arrays with the aggregate information from each of the three original arrays.
NSMutableArray* muteItem = [[NSMutableArray alloc] initWithObjects: #"a", #"b", #"b", #"c", #"c", #"c", nil];
NSMutableArray* muteQuantity = [[NSMutableArray alloc] initWithObjects: #"1", #"1", #"1", #"1", #"1", #"1", nil];
NSMutableArray* mutePrice = [[NSMutableArray alloc] initWithObjects: #"4", #"3", #"3", #"6", #"6", #"6", nil];
NSMutableArray* setItem = [NSMutableArray array];
NSMutableArray* setQuantity = [NSMutableArray array];
NSMutableArray* setPrice = [NSMutableArray array];
NSSet* itemSet = [NSSet setWithArray: muteItem];
for (NSString* key in itemSet) {
NSIndexSet* indices = [muteItem indexesOfObjectsPassingTest: ^BOOL(id obj, NSUInteger idx, BOOL *stop) {
return [obj isEqualToString: key];
}];
__block NSInteger totalQuantity = 0;
__block NSInteger totalPrice = 0;
[indices enumerateIndexesUsingBlock: ^void(NSUInteger idx, BOOL *stop) {
totalQuantity += [[muteQuantity objectAtIndex: idx] integerValue];
totalPrice += [[mutePrice objectAtIndex: idx] integerValue];
}];
[setItem addObject: key];
[setQuantity addObject: [NSNumber numberWithInteger: totalQuantity]];
[setPrice addObject: [NSNumber numberWithInteger: totalPrice]];
}
NOTE: This code assumes you are using ARC. Also, in your original code you forgot to nil terminate your array constructors.
EDIT: I notice that your prices are integers, you may want to change them to floats if your currency uses decimal fractions. This would require changing the definition of totalPrice to float and you would want to change the end of the totalPrice += line from integerValue to floatValue.
EDIT2: Renamed all variables that started with a capital letter as this violates standard naming convention. Only class names should begin with a capital letter, variables should always begin with lowercase, or an _ for instance variables. :)

Is there a more elegant way of finding unique NSDictionary keys within an NSArray?

Aim: To obtain an NSArray containing unique keys for given NSDictionary(s) using elegant code
Example Code with Current Working Solution:
NSArray *data = [[NSArray alloc] initWithObjects:
[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:1], #"a", [NSNumber numberWithInt:2], #"b", nil],
[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:3], #"b", [NSNumber numberWithInt:4], #"c", nil],
[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:5], #"a", [NSNumber numberWithInt:6], #"c", nil],
[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:7], #"b", [NSNumber numberWithInt:8], #"a", nil],
[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:8], #"c", [NSNumber numberWithInt:9], #"b", nil],
nil];
// create an NSArray of all the dictionary keys within the NSArray *data
NSMutableSet *setKeys = [[NSMutableSet alloc] init];
for (int i=0; i<[data count]; i++) {
[setKeys addObjectsFromArray:[[data objectAtIndex:i] allKeys]];
}
NSArray *arrayKeys = [setKeys allObjects];
NSLog(#"arrayKeys: %#", arrayKeys);
Which returns the desired array of keys:
2012-06-11 16:52:57.351 test.kvc[6497:403] arrayKeys: (
a,
b,
c
)
Question: Is there a more elegant way of approaching this? Surely there must be some KVC approach that can get all the keys without having to iterate through the array? I've been looking at Apple Developer Documentation and can't see a solution. Any ideas? (looking at purely elegance of code rather than performance).
Normally you could use KVC by doing something like this:
NSArray *uniqueKeys = [data valueForKeyPath:#"#distinctUnionOfArrays.allKeys";
However NSDictionary overrides the valueForKey: selector which is used by the KVC internals, so this will not work correctly.
The documentation for NSDictionary's valueForKey: method tells us that:
If key does not start with “#”, invokes objectForKey:. If key does start with “#”, strips the “#” and invokes [super valueForKey:] with the rest of the key.
So we just insert an # before allKeys:
NSArray *uniqueKeys = [data valueForKeyPath:#"#distinctUnionOfArrays.#allKeys"];
And we get what we want:
(lldb) po [data valueForKeyPath:#"#distinctUnionOfArrays.#allKeys"]
(id) $14 = 0x07bb2fc0 <__NSArrayI 0x7bb2fc0>(
c,
a,
b
)
This is less ugly, and possibly marginally faster, I suppose:
NSMutableSet *setKeys = [[NSMutableSet alloc] init];
for (NSDictionary* dict in data) {
for (id key in [dict keyEnumerator]) {
[setKeys addObject:key];
}
}
But you're not doing a particularly common operation, so I wouldn't expect to find some incredibly elegant method. If that's what you want, go learn Haskell.
You could try this:
NSMutableSet *setKeys = [[NSMutableSet alloc] init];
for(NSDictionary *dict in data) {
[setKeys addObjectsFromArray:[dict allKeys]];
}
NSArray *arrayKeys = [setKeys allObjects];
If you prefer blocks you could use this:
[data enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
[setKeys addObjectsFromArray:[obj allKeys]];
}];

arrayByAddingObjectsFromArray?

I am not sure what I am doing wrong here? I have tried various combinations to try and copy an array into variable mmm. I am trying to learn how to create a 2D array and then run a loop to place init_array into 10 columns.
// NSMutableArray *mmm = [NSMutableArray arrayWithCapacity: 20];
NSMutableArray *kkk = [NSMutableArray arrayWithObjects: #"a", #"b", #"cat", #"dog", nil];
NSMutableArray *mmm; //= [NSMutableArray arrayWithObjects: #"1", #"2", #"3", #"4", nil];
[mmm arrayByAddingObjectsFromArray:kkk];
NSLog(#"Working: %#",[mmm objectAtIndex:3]);
thanks...
so this works from the given answer:
NSMutableArray *mmm = [NSMutableArray arrayWithCapacity: 20];
NSMutableArray *kkk = [NSMutableArray arrayWithObjects: #"a", #"b", #"cat", #"dog", nil];
[mmm addObjectsFromArray:kkk];
NSLog(#"Working: %#",[mmm objectAtIndex:3]);
arrayByAddingObjectsFromArray: returns a new (autoreleased) NSArray object. What you want is addObjectsFromArray:.
arrayByAddingObjectsFromArray: returns a new NSArray that includes the objects in the receiver followed by the objects in the argument. The code you posted there, with mmm unset, will probably just crash since mmm doesn't point to an NSArray object. If you had assigned an array to mmm, then it would return (#"1", #"2", #"3", #"4", #"a", #"b", #"cat", #"dog") — but you don't assign the result to any variable, so it just goes nowhere. You'd have to do something like NSArray *yetAnotherArray = [mmm arrayByAddingObjectsFromArray:kkk].
If you have an NSMutableArray and you want to add objects from another array, use addObjectsFromArray:.

Missing sentinel in function call?

Not sure why I get "Missing sentinel in function call?"
NSMutableArray *kkk = [NSMutableArray arrayWithObjects: #"a", #"b", #"cat", #"dog", nil];
ppp = [NSMutableArray arrayWithCapacity:3];
[ppp addObject:[[NSMutableArray alloc] initWithObjects: kkk]]; // <<--- Missing sentinel in function call
[ppp addObject:[[NSMutableArray alloc] initWithObjects: kkk, nil]]; //<<--- change, but it falls out
NSLog(#"Working: %# %#", [[ppp objectAtIndex:0] objectAtIndex:3], [[ppp objectAtIndex:0] objectAtIndex:2] );
initWithObjects: must be terminated with a trailing nil. Since it is a single object, you should be a able to use initWithObject:. That said, you will be leaking the array like this. Do
[ppp addObject:[NSMutableArray arrayWithObject:kkk]];
There is one more problem with the piece of code here,
NSMutableArray *kkk = [NSMutableArray arrayWithObjects: #"a", #"b", #"cat", #"dog", nil];
ppp = [NSMutableArray arrayWithCapacity:3];
[ppp addObject:[[NSMutableArray alloc] initWithObjects: kkk, nil]];
You are creating a three dimensional array. So
NSLog(#"Working: %# %#", [[ppp objectAtIndex:0] objectAtIndex:3], [[ppp objectAtIndex:0] objectAtIndex:2] );
is wrong.
NSLog(#"Working: %# %#", [[[ppp objectAtIndex:0] objectAtIndex:0] objectAtIndex:3], [[[ppp objectAtIndex:0] objectAtIndex:0] objectAtIndex:2] );
should log proper values.
However if you need a two dimensional array based on your log statement, I would say you need to do this instead,
[ppp addObject:kkk];
You need to add nil as the last object in the list.
[ppp addObject:[[NSMutableArray alloc] initWithObjects: kkk, nil]];
Basically it tells the method to stop looking for more objects. Without that, it can look at a bad pointer and crash.