how can I count how many itens do I have inside of "bills"?
bills = (
{
id = 1;
name = "Cursus Nibh Venenatis";
value = "875.24";
},
{
id = 2;
name = "Elit Fusce";
value = "254.02";
}
);
I'm counting this way:
NSUInteger keyCount = [resultsDictionary count];
NSLog(#"%i", keyCount);
Thanks!
A naive solution would assume the OP wants to count bills, which happens to be an array, so the solution would be
NSLog(#"Count: %i", [[resultsDictionary objectForKey: #"bills"] count]);
However, if you have a dictionary with more than one object you want to count, then enumerating them all is the only way to go.
NSUInteger keyCount = [resultsDictionary count];
NSLog(#"%i", keyCount);
is true but also you can use [resultsDictionary allKeys]; which will return an array of keys and you can directly get its count. For more, please visit docs :v
NSMutableArray *billsArray =[[NSMutableArray alloc] init];
billsArray = [resultsDictionary valueForKey:#"bills"];//returns array
NSUInteger keyCount = [billsArray count];
NSLog(#"%i", keyCount);
I think it will be helpful to you.
NSUInteger count = [bills count]; // top level items in the dictionary
If you want to get ALL items, then you need to use block enumeration and recursively ask every dictionary what the count is and then sum. You have to write code - there is no system provided method to do this. Look at the block enumerations (ie enumerate....) in the class reference.
you can also ask each item what it is - and if "isKindOf:" a NSDictionary or NSArray, get the count, otherwise treat it as 1.
Related
I have an NSArray containing objects with a size property.
How can I check if the NSArray has two objects with the same value for size?
Can I do something like:
int i = 0;
for (id item1 in myArray) {
NSDecimalNumber *size1 = [item1 size];
for (id item2 in myArray) {
NSDecimalNumber *size2 = [item2 size];
if ([size1 isEqual:size2]) {
i ++;
}
}
}
if (i > [myArray count]) {
NSLog(#"Duplicate Sizes Exist");
}
Or is there an easier way?
Try this code:
NSSet *myset = [NSSet setWithArray:[myarray valueForKey:#"size"]];
int duplicatesCount = [myarray count] - [myset count];
size here is the object property.
Use NSCountedSet. then add all your objects to the counted set, and use the countForObject: method to find out how often each object appears in your array.
You can check this link also how-to-find-duplicate-values-in-arrays
Hope it helps you
Probably simplest is to sort the array based on the size field and then step through the sorted list looking for adjacent dupes.
You could also "wrap" each object in one that exports the size as its key and use a set. But that's a lot of extra allocations.
But if you only want to know if dupes exist, and not which ones they are, create an NSNumber for each object's size and insert the NSNumbers in a set. The final size will tell you how many dupes.
NSArray *cleanedArray = [[NSSet setWithArray:yourArraywithDuplicatesObjects ] allObjects];
Use Sets this will remove all duplicates objects.Will return NSArrayNSCountedSet and use countForObject: method to find out how often each object appears how many times.
I've been trying to figure out a way of checking how many of a certain object are in an NSArray.
I've looked through the docs and I'm pretty sure there is no premade method for this. Also I can't find anything here on SO.
Do anybody know about a good way to do this? Because I seriously can't come up with anything.
In this specific case I have an array with strings (most cases several of each) and I want to count how many strings in the array that matches to whatever I ask for.
If this is a primary use of the data structure and order doesn't matter, consider switching to an NSCountedSet which is specifically for solving this problem efficiently.
If you need an ordered collection, and you don't have a huge set of objects, than the fast enumeration answers are the best approach.
If you want to know where the objects are, then use indexesOfObjectsPassingTest:.
If you have a huge number of object, I would look at indexesOfObjectsWithOptions:passingTest: with the NSEnumerationConcurrent option. This will allow you to search the array on multiple cores. (This is only possibly faster on a multi-core device, and even then is probably only faster if you have a very large collection. You should absolutely test before assuming that concurrent will be faster.) Even if you just need the final count, it may be faster for certain data sets to use this method and then use count on the final index set.
There actually is a method for this: - (NSIndexSet *)indexesOfObjectsPassingTest:(BOOL (^)(id obj, NSUInteger idx, BOOL *stop))predicate
NSIndexSet *indexes = [array indexesOfObjectsPassingTest:^(id obj, NSUInteger index, BOOL *stop) {
return [obj isEqualTo:myOtherObject];
}];
Sounds like a case for NSCountedSet, which does what you are after with its initWithArray: initializer:
// Example array of strings
NSArray *array = [NSArray arrayWithObjects:
#"Joe", #"Jane", #"Peter", #"Paul",
#"Joe", #"Peter", #"Paul",
#"Joe",
#"Jane", #"Peter",
nil];
NSCountedSet *countedSet = [[NSCountedSet alloc] initWithArray: array];
// for-in will let you loop over the counted set
for (NSString *str in countedSet) {
NSLog(#"Count of %#: %ld", str, (long)[countedSet countForObject:str]);
}
One approach would be to iterate and check.
- (int)repeatsOf:(NSString *)repeater inArray:(NSArray *)array {
int count = 0;
for (NSString *item in array) {
if ([item isEqualToString:repeater]) {
count++;
}
}
return count;
}
You could try a simple loop. Suppose needle is your reference string and array is your NSArray of strings:
unsigned int n = 0;
for (NSString * str in array)
{
if ([needle isEqualToString:str])
{
++n;
}
}
Now n holds the count of strings in equal to needle.
You could define a function like this:
- (int)countStringsThatMatch:(NSString*)match inArray:(NSArray*)array
{
int matches = 0;
for (id string in array) {
if ([string isEqualToString:match]) {
matches++;
}
}
return matches;
}
And then use it like:
int count = [self countStringsThatMatch:#"someString" inArray:someArray];
- (NSUInteger) objectCountInArray:(NSArray *)array
matchingString:(NSString *)stringToMatch {
NSUInteger count = 0;
for (NSString *string in array) {
count += [string isEqualToString:stringToMatch] ? 1 : 0;
}
return count;
}
You can try to expand this to use a block that gets an object and returns a BOOL. Then you can use it to compare an array of whatever you want.
This question already has answers here:
Objective-C: Count the number of times an object occurs in an array?
(12 answers)
Closed 8 years ago.
I need a way of counting how many time an object occurs in any given MutableArray and then returning the indexes of the objects into a seperate Mutable Array. Ive tried doing this a couple of ways but cant figure it out.
So basically say I have an array containing 2,3,3,4,3,5,3 When searching for 3, it should give me both the number of times, 4, and a seperate array containing 1,2,4,6 (the indexes of the objects.
I saw the following code already here on the site, but cant work out how to modify it, can anyone help me?
int occurrences = 0;
for(NSString *string in array){
occurrences += ([string isEqualToString:#"Apple"]?1:0); //certain object is #"Apple"
}
int occurrences = 0;
NSMutableArray *indices = [NSMutableArray array];
int i = 0;
for (i = 0; i < [array count]; i++) {
NSString *obj = [array objectAtIndex:i];
if ([obj isEqualToString:#"Apple"]) {
occurrences++;
[indices addObject:[NSNumber numberWithInt:i]];
}
}
You also could drop the tracking with occurrences and do something like
int occurrences = [indices count];
after the for loop.
id thingYouAreLookingFor;
NSIndexSet *result = [array indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
return [thingYouAreLookingFor equals: obj];
}];
Easy way to do it if you don't mind time, it's a square time operation.
Keep a counter, recording how many elements from array1 has appeared in array2
for all element in array1, test if it exist in array2. If it exist, counter++, if not, continue.
return the counter.
Use [myMutableArray containsObject:parameter] to return a boolean of wether array2 contains an element or not.
So I have an NSDictionary where the keys are years as NSString's and the value for each key is also an NSString which is sort of a description for the year. So for example, one key is "943 B.C.", another "1886". The problem I am encountering is that I want to sort them, naturally, in ascending order.
The thing is that the data source of these years is already in order, it's just that when I go ahead and call setValue:forKey the order is lost, naturally. I imagine figuring out a way to sort these NSString's might be a pain and instead I should look for a method of preserving the order at the insertion phase. What should I do? Should I instead make this an NSMutableArray in which every object is actually an NSDictionary consisting of the key being the year and the value being the description?
I guess I just answered my own question, but to avoid having wasted this time I'll leave this up in case anyone can recommend a better way of doing this.
Thanks!
EDIT: I went ahead with my own idea of NSMutableArray with NSDictionary entries to hold the key/value pairs. This is how I am accessing the information later on, hopefully I'm doing this correctly:
// parsedData is the NSMutableArray which holdes the NSDictionary entries
for (id entry in parsedData) {
NSString *year = [[entry allKeys] objectAtIndex:0];
NSString *text = [entry objectForKey:year];
NSLog(#"Year: %#, Text: %#", year, text);
}
Maintain a NSMutableArray to store the keys in order, in addition to the NSDictionary which holds all key-value pairs.
Here is a similar question.
You could either do it as an array of dictionaries, as you suggest, or as an array of strings where the strings are the keys to your original dictionary. The latter is probably a simpler way of going about it. NSDictionary does not, as I understand it, maintain any particular ordering of its keys, so attempting to sort the values there may be unwise.
I needed to solve a similar problem to sort strings of operating system names, such as "Ubuntu 10.04 (lucid)".
In my case, the string could have any value, so I sort by tokenizing and testing to see if a token is a number. I'm also accounting for a string like "8.04.2" being considered a number, so I have a nested level of tokenizing. Luckily, the nested loop is typically only one iteration.
This is from the upcoming OpenStack iPhone app.
- (NSComparisonResult)compare:(ComputeModel *)aComputeModel {
NSComparisonResult result = NSOrderedSame;
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
NSArray *tokensA = [self.name componentsSeparatedByString:#" "];
NSArray *tokensB = [aComputeModel.name componentsSeparatedByString:#" "];
for (int i = 0; (i < [tokensA count] || i < [tokensB count]) && result == NSOrderedSame; i++) {
NSString *tokenA = [tokensA objectAtIndex:i];
NSString *tokenB = [tokensB objectAtIndex:i];
// problem: 8.04.2 is not a number, so we need to tokenize again on .
NSArray *versionTokensA = [tokenA componentsSeparatedByString:#"."];
NSArray *versionTokensB = [tokenB componentsSeparatedByString:#"."];
for (int j = 0; (j < [versionTokensA count] || j < [versionTokensB count]) && result == NSOrderedSame; j++) {
NSString *versionTokenA = [versionTokensA objectAtIndex:j];
NSString *versionTokenB = [versionTokensB objectAtIndex:j];
NSNumber *numberA = [formatter numberFromString:versionTokenA];
NSNumber *numberB = [formatter numberFromString:versionTokenB];
if (numberA && numberB) {
result = [numberA compare:numberB];
} else {
result = [versionTokenA compare:versionTokenB];
}
}
}
[formatter release];
return result;
}
In Cocoa, if I want to loop through an NSMutableArray and remove multiple objects that fit a certain criteria, what's the best way to do this without restarting the loop each time I remove an object?
Thanks,
Edit: Just to clarify - I was looking for the best way, e.g. something more elegant than manually updating the index I'm at. For example in C++ I can do;
iterator it = someList.begin();
while (it != someList.end())
{
if (shouldRemove(it))
it = someList.erase(it);
}
For clarity I like to make an initial loop where I collect the items to delete. Then I delete them. Here's a sample using Objective-C 2.0 syntax:
NSMutableArray *discardedItems = [NSMutableArray array];
for (SomeObjectClass *item in originalArrayOfItems) {
if ([item shouldBeDiscarded])
[discardedItems addObject:item];
}
[originalArrayOfItems removeObjectsInArray:discardedItems];
Then there is no question about whether indices are being updated correctly, or other little bookkeeping details.
Edited to add:
It's been noted in other answers that the inverse formulation should be faster. i.e. If you iterate through the array and compose a new array of objects to keep, instead of objects to discard. That may be true (although what about the memory and processing cost of allocating a new array, and discarding the old one?) but even if it's faster it may not be as big a deal as it would be for a naive implementation, because NSArrays do not behave like "normal" arrays. They talk the talk but they walk a different walk. See a good analysis here:
The inverse formulation may be faster, but I've never needed to care whether it is, because the above formulation has always been fast enough for my needs.
For me the take-home message is to use whatever formulation is clearest to you. Optimize only if necessary. I personally find the above formulation clearest, which is why I use it. But if the inverse formulation is clearer to you, go for it.
One more variation. So you get readability and good performace:
NSMutableIndexSet *discardedItems = [NSMutableIndexSet indexSet];
SomeObjectClass *item;
NSUInteger index = 0;
for (item in originalArrayOfItems) {
if ([item shouldBeDiscarded])
[discardedItems addIndex:index];
index++;
}
[originalArrayOfItems removeObjectsAtIndexes:discardedItems];
This is a very simple problem. You just iterate backwards:
for (NSInteger i = array.count - 1; i >= 0; i--) {
ElementType* element = array[i];
if ([element shouldBeRemoved]) {
[array removeObjectAtIndex:i];
}
}
This is a very common pattern.
Some of the other answers would have poor performance on very large arrays, because methods like removeObject: and removeObjectsInArray: involve doing a linear search of the receiver, which is a waste because you already know where the object is. Also, any call to removeObjectAtIndex: will have to copy values from the index to the end of the array up by one slot at a time.
More efficient would be the following:
NSMutableArray *array = ...
NSMutableArray *itemsToKeep = [NSMutableArray arrayWithCapacity:[array count]];
for (id object in array) {
if (! shouldRemove(object)) {
[itemsToKeep addObject:object];
}
}
[array setArray:itemsToKeep];
Because we set the capacity of itemsToKeep, we don't waste any time copying values during a resize. We don't modify the array in place, so we are free to use Fast Enumeration. Using setArray: to replace the contents of array with itemsToKeep will be efficient. Depending on your code, you could even replace the last line with:
[array release];
array = [itemsToKeep retain];
So there isn't even a need to copy values, only swap a pointer.
You can use NSpredicate to remove items from your mutable array. This requires no for loops.
For example if you have an NSMutableArray of names, you can create a predicate like this one:
NSPredicate *caseInsensitiveBNames =
[NSPredicate predicateWithFormat:#"SELF beginswith[c] 'b'"];
The following line will leave you with an array that contains only names starting with b.
[namesArray filterUsingPredicate:caseInsensitiveBNames];
If you have trouble creating the predicates you need, use this apple developer link.
I did a performance test using 4 different methods. Each test iterated through all elements in a 100,000 element array, and removed every 5th item. The results did not vary much with/ without optimization. These were done on an iPad 4:
(1) removeObjectAtIndex: -- 271 ms
(2) removeObjectsAtIndexes: -- 1010 ms (because building the index set takes ~700 ms; otherwise this is basically the same as calling removeObjectAtIndex: for each item)
(3) removeObjects: -- 326 ms
(4) make a new array with objects passing the test -- 17 ms
So, creating a new array is by far the fastest. The other methods are all comparable, except that using removeObjectsAtIndexes: will be worse with more items to remove, because of the time needed to build the index set.
Either use loop counting down over indices:
for (NSInteger i = array.count - 1; i >= 0; --i) {
or make a copy with the objects you want to keep.
In particular, do not use a for (id object in array) loop or NSEnumerator.
For iOS 4+ or OS X 10.6+, Apple added passingTest series of APIs in NSMutableArray, like – indexesOfObjectsPassingTest:. A solution with such API would be:
NSIndexSet *indexesToBeRemoved = [someList indexesOfObjectsPassingTest:
^BOOL(id obj, NSUInteger idx, BOOL *stop) {
return [self shouldRemove:obj];
}];
[someList removeObjectsAtIndexes:indexesToBeRemoved];
Nowadays you can use reversed block-based enumeration. A simple example code:
NSMutableArray *array = [#[#{#"name": #"a", #"shouldDelete": #(YES)},
#{#"name": #"b", #"shouldDelete": #(NO)},
#{#"name": #"c", #"shouldDelete": #(YES)},
#{#"name": #"d", #"shouldDelete": #(NO)}] mutableCopy];
[array enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if([obj[#"shouldDelete"] boolValue])
[array removeObjectAtIndex:idx];
}];
Result:
(
{
name = b;
shouldDelete = 0;
},
{
name = d;
shouldDelete = 0;
}
)
another option with just one line of code:
[array filterUsingPredicate:[NSPredicate predicateWithFormat:#"shouldDelete == NO"]];
In a more declarative way, depending on the criteria matching the items to remove you could use:
[theArray filterUsingPredicate:aPredicate]
#Nathan should be very efficient
Here's the easy and clean way. I like to duplicate my array right in the fast enumeration call:
for (LineItem *item in [NSArray arrayWithArray:self.lineItems])
{
if ([item.toBeRemoved boolValue] == YES)
{
[self.lineItems removeObject:item];
}
}
This way you enumerate through a copy of the array being deleted from, both holding the same objects. An NSArray holds object pointers only so this is totally fine memory/performance wise.
Add the objects you want to remove to a second array and, after the loop, use -removeObjectsInArray:.
this should do it:
NSMutableArray* myArray = ....;
int i;
for(i=0; i<[myArray count]; i++) {
id element = [myArray objectAtIndex:i];
if(element == ...) {
[myArray removeObjectAtIndex:i];
i--;
}
}
hope this helps...
Why don't you add the objects to be removed to another NSMutableArray. When you are finished iterating, you can remove the objects that you have collected.
How about swapping the elements you want to delete with the 'n'th element, 'n-1'th element and so on?
When you're done you resize the array to 'previous size - number of swaps'
If all objects in your array are unique or you want to remove all occurrences of an object when found, you could fast enumerate on an array copy and use [NSMutableArray removeObject:] to remove the object from the original.
NSMutableArray *myArray;
NSArray *myArrayCopy = [NSArray arrayWithArray:myArray];
for (NSObject *anObject in myArrayCopy) {
if (shouldRemove(anObject)) {
[myArray removeObject:anObject];
}
}
benzado's anwser above is what you should do for preformace. In one of my applications removeObjectsInArray took a running time of 1 minute, just adding to a new array took .023 seconds.
I define a category that lets me filter using a block, like this:
#implementation NSMutableArray (Filtering)
- (void)filterUsingTest:(BOOL (^)(id obj, NSUInteger idx))predicate {
NSMutableIndexSet *indexesFailingTest = [[NSMutableIndexSet alloc] init];
NSUInteger index = 0;
for (id object in self) {
if (!predicate(object, index)) {
[indexesFailingTest addIndex:index];
}
++index;
}
[self removeObjectsAtIndexes:indexesFailingTest];
[indexesFailingTest release];
}
#end
which can then be used like this:
[myMutableArray filterUsingTest:^BOOL(id obj, NSUInteger idx) {
return [self doIWantToKeepThisObject:obj atIndex:idx];
}];
A nicer implementation could be to use the category method below on NSMutableArray.
#implementation NSMutableArray(BMCommons)
- (void)removeObjectsWithPredicate:(BOOL (^)(id obj))predicate {
if (predicate != nil) {
NSMutableArray *newArray = [[NSMutableArray alloc] initWithCapacity:self.count];
for (id obj in self) {
BOOL shouldRemove = predicate(obj);
if (!shouldRemove) {
[newArray addObject:obj];
}
}
[self setArray:newArray];
}
}
#end
The predicate block can be implemented to do processing on each object in the array. If the predicate returns true the object is removed.
An example for a date array to remove all dates that lie in the past:
NSMutableArray *dates = ...;
[dates removeObjectsWithPredicate:^BOOL(id obj) {
NSDate *date = (NSDate *)obj;
return [date timeIntervalSinceNow] < 0;
}];
Iterating backwards-ly was my favourite for years , but for a long time I never encountered the case where the 'deepest' ( highest count) object was removed first. Momentarily before the pointer moves on to the next index there ain't anything and it crashes.
Benzado's way is the closest to what i do now but I never realised there would be the stack reshuffle after every remove.
under Xcode 6 this works
NSMutableArray *itemsToKeep = [NSMutableArray arrayWithCapacity:[array count]];
for (id object in array)
{
if ( [object isNotEqualTo:#"whatever"]) {
[itemsToKeep addObject:object ];
}
}
array = nil;
array = [[NSMutableArray alloc]initWithArray:itemsToKeep];