iphone index of array with dictionaries - iphone

i have an array with dictionaries,
. how to get the index for a specific dictionary... [where I got the data for the dictionary i want to find, but need the index is on]
NSMutableDictionary *dictois = [[NSMutableDictionary alloc]init];
[dictois setObject:#"easySpritedd" forKey:#"Nombre"];
[dictois setObject:#"X" forKey:#"290"];
[dictois setObject:#"Y" forKey:#"300"];
int fooIndex = [self.bloquesArray indexOfObject: dictois];
but as you see i dont know yet how to get the dictionary for comparing in the indexOfObject
thanks!

NSDictionary objects have the following comparison methods:
- (BOOL)isEqualToDictionary:(NSDictionary *)otherDictionary
With the following discussion
Two dictionaries have equal contents if they each hold the same number
of entries and, for a given key, the corresponding value objects in
each dictionary satisfy the isEqual: test.
This should be the case for you. Sadly you cannot change the method which NSArray uses to calculate the indexOfObject: so it can't help you, hence the solution provided by Denis is the best I can think of (unless you fancy subclassing NSArray which I wouldn't recommend).
Just as a complement to Denis' answer you could use the NSArray method
- (NSIndexSet *)indexesOfObjectsPassingTest:(BOOL (^)(id obj, NSUInteger idx, BOOL *stop))predicate
instead of
- (NSUInteger)indexOfObjectPassingTest:(BOOL (^)(id obj, NSUInteger idx, BOOL *stop))predicate
If having several equal objects in the array is a possibility.

Use the following code
NSMutableDictionary *dictois = [[NSMutableDictionary new]autorelease];
[dictois setObject:#"easySpritedd" forKey:#"Nombre"];
[dictois setObject:#"X" forKey:#"290"];
[dictois setObject:#"Y" forKey:#"300"];
int fooIndex = [self.bloquesArray indexOfObjectPassingTest: ^(id obj, NSUInteger idx, BOOL *stop){
if( [[obj class] isKindOfClass: [NSDictionary class]] ) {
BOOL result = [obj isEqualToDictionary: diction];
*stop = result;
return result;
}
*stop = NO;
return NO;
}];

Related

NSArray full of NSDictionaries. How to find index of object?

I have an array which is filled with NSDictionaries. I want to find the index of one of the dictionary, but what I know about this dictionary is only a value for key #"name".
How do I do it ?
Find index of first dictionary in theArray whose value for #"name" is theValue:
NSUInteger index = [theArray indexOfObjectPassingTest:
^BOOL(NSDictionary *dict, NSUInteger idx, BOOL *stop)
{
return [[dict objectForKey:#"name"] isEqual:theValue];
}
];
index will be NSNotFound if no matching object is found.
NSArray *temp = [allList valueForKey:#"Name"];
NSInteger indexValue = [temp indexOfObject:YourText];
NSString *name = [[allList objectAtIndex:indexValue] valueForKey:#"Name"]

count number of dictionaries within a dictionary

my questions is about iPhone development.
I'm trying to figure out if there is a way to count ONLY the number of dictionaries within a dictionary.
for example, let's say this is my dictionary
Dictionary contains 5 elements:
string
string
NSDictionary
NSDictionary
NSDictionary
I would like to count only the NSDictionaries... so the return value should be 3.
Is there any way to accomplish this?
Thanks.
NSSet *dictKeys = [myDict keysOfEntriesPassingTest:^(id key, id obj, BOOL *stop) {
return [obj isKindOfClass:[NSDictionary class]];
}];
NSUInteger numberOfDicts = [dictKeys count];
NSDictionary* root = ...;
__block NSUInteger count = 0;
[root enumerateKeysAndObjectsUsingBlock: ^(id key, id obj, BOOL* stop) {
if ( [obj isKindOfClass: NSDictionary.class] ) ++ count;
*stop = NO;
}];
Of course
NSUInteger count = 0;
for (id obj in root) {
if ( [obj isKindOfClass: NSDictionary.class] ) ++ count;
}
will work as well.
__block NSInteger countOfDictionaries = 0;
[dictionary enumerateKeysAndObjectsUsingBlock:(void (^)(id key, id obj, BOOL *stop))block {
if ([obj isKindOfClass:[NSDictionary class]]) {
countOfDictionaries++;
}
}];
As shown above, simply enumerate through every object of your dictionary and keep a count of every object that is an "NSDictionary", by testing the class of the object.
Loop through your NSDictionary by using NSEnumrator and do the following test :
if ([myObject class] == [NSDictionary class]) c++;

How do I get the index of an object in an NSArray using string value?

I want to get the index of an object within the NSMutableArray of categories.
The category object has an attribute "category_title" and I want to be able to get the index by passing the value of category_title.
I have looked through the docs and can't find a simple way to go about this.
NSArray does not guarantee that you can only store one copy of a given object, so you have to make sure that you handle that yourself (or use NSOrderedSet).
That said, there are a couple approaches here. If your category objects implement isEqual: to match category_title, then you can just use -indexOfObject:.
If you can't do that (because the category objects use a different definition of equality), use -indexOfObjectPassingTest:. It takes a block in which you can do whatever test you want to define your "test" - in this case, testing category_title string equality.
Note that these are all declared for NSArray, so you won't see them if you are only looking at the NSMutableArray header/documentation.
EDIT: Code sample. This assumes objects of class CASCategory with an NSString property categoryTitle (I can't bring myself to put underscores in an ivar name :-):
CASCategory *cat1 = [[CASCategory alloc] init];
[cat1 setCategoryTitle:#"foo"];
CASCategory *cat2 = [[CASCategory alloc] init];
[cat2 setCategoryTitle:#"bar"];
CASCategory *cat3 = [[CASCategory alloc] init];
[cat3 setCategoryTitle:#"baz"];
NSMutableArray *array = [NSMutableArray arrayWithObjects:cat1, cat2, cat3, nil];
[cat1 release];
[cat2 release];
[cat3 release];
NSUInteger barIndex = [array indexOfObjectPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
if ([[(CASCategory *)obj categoryTitle] isEqualToString:#"bar"]) {
*stop = YES;
return YES;
}
return NO;
}];
if (barIndex != NSNotFound) {
NSLog(#"The title of category at index %lu is %#", barIndex, [[array objectAtIndex:barIndex] categoryTitle]);
}
else {
NSLog(#"Not found");
}
Not sure that I understand the question but something like this might work (assuming the Mutable Array contains objects of Class "Category"):
int indx;
bool chk;
for (Category *aCategory in theArray)
{
chk = ([[aCategory category_title] isEqualToString:#"valOfCategoryTitle"])
if ( chk )
indx = [theArray indexOfObject:aCategory];
}
Try this code much more simpler:-
int f = [yourArray indexOfObject:#"yourString"];

NSArray Equivalent of Map

Given an NSArray of NSDictionary objects (containing similar objects and keys) is it possible to write perform a map to an array of specified key? For example, in Ruby it can be done with:
array.map(&:name)
It only saves a couple lines, but I use a category on NSArray. You need to ensure your block never returns nil, but other than that it's a time saver for cases where -[NSArray valueForKey:] won't work.
#interface NSArray (Map)
- (NSArray *)mapObjectsUsingBlock:(id (^)(id obj, NSUInteger idx))block;
#end
#implementation NSArray (Map)
- (NSArray *)mapObjectsUsingBlock:(id (^)(id obj, NSUInteger idx))block {
NSMutableArray *result = [NSMutableArray arrayWithCapacity:[self count]];
[self enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
[result addObject:block(obj, idx)];
}];
return result;
}
#end
Usage is much like -[NSArray enumerateObjectsWithBlock:]:
NSArray *people = #[
#{ #"name": #"Bob", #"city": #"Boston" },
#{ #"name": #"Rob", #"city": #"Cambridge" },
#{ #"name": #"Robert", #"city": #"Somerville" }
];
// per the original question
NSArray *names = [people mapObjectsUsingBlock:^(id obj, NSUInteger idx) {
return obj[#"name"];
}];
// (Bob, Rob, Robert)
// you can do just about anything in a block
NSArray *fancyNames = [people mapObjectsUsingBlock:^(id obj, NSUInteger idx) {
return [NSString stringWithFormat:#"%# of %#", obj[#"name"], obj[#"city"]];
}];
// (Bob of Boston, Rob of Cambridge, Robert of Somerville)
I've no idea what that bit of Ruby does but I think you are looking for NSArray's implementation of -valueForKey:. This sends -valueForKey: to every element of the array and returns an array of the results. If the elements in the receiving array are NSDictionaries, -valueForKey: is nearly the same as -objectForKey:. It will work as long as the key doesn't start with an #
To summarize all other answers:
Ruby (as in the question):
array.map{|o| o.name}
Obj-C (with valueForKey):
[array valueForKey:#"name"];
Obj-C (with valueForKeyPath, see KVC Collection Operators):
[array valueForKeyPath:#"[collect].name"];
Obj-C (with enumerateObjectsUsingBlock):
NSMutableArray *newArray = [NSMutableArray array];
[array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
[newArray addObject:[obj name]];
}];
Swift (with map, see closures)
array.map { $0.name }
And, there are a couple of libraries that allow you to handle arrays in a more functional way. CocoaPods is recommended to install other libraries.
Update: If you're using Swift, see map.
BlocksKit is an option:
NSArray *new = [stringArray bk_map:^id(NSString *obj) {
return [obj stringByAppendingString:#".png"];
}];
Underscore is another option. There is a map function, here is an example from the website:
NSArray *tweets = Underscore.array(results)
// Let's make sure that we only operate on NSDictionaries, you never
// know with these APIs ;-)
.filter(Underscore.isDictionary)
// Remove all tweets that are in English
.reject(^BOOL (NSDictionary *tweet) {
return [tweet[#"iso_language_code"] isEqualToString:#"en"];
})
// Create a simple string representation for every tweet
.map(^NSString *(NSDictionary *tweet) {
NSString *name = tweet[#"from_user_name"];
NSString *text = tweet[#"text"];
return [NSString stringWithFormat:#"%#: %#", name, text];
})
.unwrap;
I think valueForKeyPath is a good choice.
Sit below has very cool examples. Hopes it is helpful.
http://kickingbear.com/blog/archives/9
Some example:
NSArray *names = [allEmployees valueForKeyPath: #"[collect].{daysOff<10}.name"];
NSArray *albumCovers = [records valueForKeyPath:#"[collect].{artist like 'Bon Iver'}.<NSUnarchiveFromDataTransformerName>.albumCoverImageData"];
I'm no Ruby expert so I'm not 100% confident I'm answering correctly, but based on the interpretation that 'map' does something to everything in the array and produces a new array with the results, I think what you probably want is something like:
NSMutableArray *replacementArray = [NSMutableArray array];
[existingArray enumerateObjectsUsingBlock:
^(NSDictionary *dictionary, NSUInteger idx, BOOL *stop)
{
NewObjectType *newObject = [something created from 'dictionary' somehow];
[replacementArray addObject:newObject];
}
];
So you're using the new support for 'blocks' (which are closures in more general parlance) in OS X 10.6/iOS 4.0 to perform the stuff in the block on everything in the array. You're choosing to do some operation and then add the result to a separate array.
If you're looking to support 10.5 or iOS 3.x, you probably want to look into putting the relevant code into the object and using makeObjectsPerformSelector: or, at worst, doing a manual iteration of the array using for(NSDictionary *dictionary in existingArray).
#implementation NSArray (BlockRockinBeats)
- (NSArray*)mappedWithBlock:(id (^)(id obj, NSUInteger idx))block {
NSMutableArray* result = [NSMutableArray arrayWithCapacity:self.count];
[self enumerateObjectsUsingBlock:^(id currentObject, NSUInteger index, BOOL *stop) {
id mappedCurrentObject = block(currentObject, index);
if (mappedCurrentObject)
{
[result addObject:mappedCurrentObject];
}
}];
return result;
}
#end
A slight improvement upon a couple of the answers posted.
Checks for nil—you can use nil to remove objects as you're mapping
Method name better reflects that the method doesn't modify the array it's called on
This is more a style thing but I've IMO improved the argument names of the block
Dot syntax for count
For Objective-C, I would add the ObjectiveSugar library to this list of answers: https://github.com/supermarin/ObjectiveSugar
Plus, its tagline is "ObjectiveC additions for humans. Ruby style." which should suit OP well ;-)
My most common use-case is mapping an dictionary returned by a server call to an array of simpler objects e.g. getting an NSArray of NSString IDs from your NSDictionary posts:
NSArray *postIds = [results map:^NSString*(NSDictionary* post) {
return [post objectForKey:#"post_id"];
}];
For Objective-C, I would add the Higher-Order-Functions to this list of answers: https://github.com/fanpyi/Higher-Order-Functions;
There is a JSON array studentJSONList like this:
[
{"number":"100366","name":"Alice","age":14,"score":80,"gender":"female"},
{"number":"100368","name":"Scarlett","age":15,"score":90,"gender":"female"},
{"number":"100370","name":"Morgan","age":16,"score":69.5,"gender":"male"},
{"number":"100359","name":"Taylor","age":14,"score":86,"gender":"female"},
{"number":"100381","name":"John","age":17,"score":72,"gender":"male"}
]
//studentJSONList map to NSArray<Student *>
NSArray *students = [studentJSONList map:^id(id obj) {
return [[Student alloc]initWithDictionary:obj];
}];
// use reduce to get average score
NSNumber *sum = [students reduce:#0 combine:^id(id accumulator, id item) {
Student *std = (Student *)item;
return #([accumulator floatValue] + std.score);
}];
float averageScore = sum.floatValue/students.count;
// use filter to find all student of score greater than 70
NSArray *greaterthan = [students filter:^BOOL(id obj) {
Student *std = (Student *)obj;
return std.score > 70;
}];
//use contains check students whether contain the student named 'Alice'
BOOL contains = [students contains:^BOOL(id obj) {
Student *std = (Student *)obj;
return [std.name isEqual:#"Alice"];
}];
There is a special key-path operator for this: #unionOfObjects. Probably it replaced [collect] from previous versions.
Imagine a Transaction class with payee property:
NSArray *payees = [self.transactions valueForKeyPath:#"#unionOfObjects.payee"];
Apple docs on Array Operators in Key-Value coding.
Swift introduces a new map function.
Here is an example from the documentation:
let digitNames = [
0: "Zero", 1: "One", 2: "Two", 3: "Three", 4: "Four",
5: "Five", 6: "Six", 7: "Seven", 8: "Eight", 9: "Nine"
]
let numbers = [16, 58, 510]
let strings = numbers.map {
(var number) -> String in
var output = ""
while number > 0 {
output = digitNames[number % 10]! + output
number /= 10
}
return output
}
// strings is inferred to be of type String[]
// its value is ["OneSix", "FiveEight", "FiveOneZero"]
The map function takes a closure which returns a value of any type and maps the existing values in the array to instances of this new type.

Gather the count of a specific object from NSMutableArray

Hey guys & girls,
Im wondering how I can find the object count of a specific type of object in an array.
For example, i have 6 'clouds' in NSMutableArray at random locations, I also have 4 'dragons' in this NSMutableArray.
How can i gather the integer 6?
I was thinking something along the lines of:
int z = [[SomeClass *clouds in _somearray] count];
Any assistance would be greatly appreciated.
Thnx,
Oliver.
Yet another way is in using blocks:
Class cloadClass = NSClassFromString(#"Cloud");
NSArray *a = /* you array with clouds and dragons */;
NSIndexSet *clouds = [a indexesOfObjectsPassingTest:
^(id obj, NSUInteger idx, BOOL *stop) {
return [obj isKindOfClass:cloadClass];
}];
// now we can count clouds
NSLog(#"%d", [clouds count]);
// but also we now can return our clouds immediately and
NSLog(#"%#", [a objectsAtIndexes:clouds]);
int result = 0;
for (NSObject *object in _somearray) {
if ([object isKindOfClass:[SomeClass class]])
result++;
}
result is the count you are looking for
If you're looking for how many times a specific instance of an object appears, you can do:
NSCountedSet *counts = [NSCountedSet setWithArray:myArrayOfObjects];
NSUInteger count = [counts countForObject:myObject];
Otherwise you'd just have to loop through the array manually and count.