Objective-C group and count distinct entries - objective-c

This is a core function question. I always dealt with this problem on the database side, by I can't do it for this case and I am stumped. I want to count the distinct values. Let's say I have an array
Array = {a,a,a,a,b,b,b,b,c,c,c,c}
And what I want is simply to get
Result = {[a,4],[b,4],[c,4]} or
ResultDistinct = { a, b, c} , ResultCount = {4,4,4}
I am fine with whatever format as long as it is fast and neat.

Use NSCountedSet.
NSArray *myArray = ... // array with all the a, b, and c values
NSCountedSet *set = [[NSCountedSet alloc] initWithArray:myArray];
for (id obj in set) {
NSLog(#"There are %d instances of %#", [set countForObject:obj], obj);
}

Related

How to sum all values in NSMutableDictionary with the same key?

I have a NSMutableDictionary in my objective c class with different pair keys values.
({Name=John; date=20070506; type=5; value= 125;},
{Name=Tracy; date=20040506; type=2; value = 237; },
{Name=Tracy; date=20040506; type=5; value = 124; },
...)
I can sum all values with the next code, but I can't get this in the same object in NSMutableDictionary.
NSNumber *amountSum = [CATransaction valueForKeyPath:#"#sum.value"];
How could I sum the values for all objects with the same type and show this like one unique object? For example:
({Name=John; date=20070506; type=5; value= 249;},
{Name=Tracy; date=20040506; type=2; value = 237; },
...)
Could I use a collection operator like this: Collections operators to do this??
thanks!
Get all the values for that valueForKey, so [Yourarray valueForKey:#"keyName"] will give you each value and finally you can loop over and sum all the values in array.
int total=0;
NSMutableDictionary *yourMutableDict=[[NSMutableDictionary alloc] init];
for (;;)
{
int value=[[Yourarray objectAtindex:i] valueForKey:#"keyName"];
total=total+value;
}
[yourMutableDict setValue:[NSNumber numberWithInteger:total] forKey:#"mySUM"];
NSLog(#"%#",[yourMutableDict objectForKey:#"mySUM"]);

Loop Through NSArray And Check Objects in Objective-C

I'm trying to loop inside the objects of my array and would like to know how can I check the contents of the objects inside it and then do something when my search doesn't apply.
For example:
myArray = #[#"A1", #"A2", #"A3", #"B1", #"B2", #"B3", #"C1", #"C2", #"C3"];
I'd like to check the contents of myArray and if the object contains the letter A, I'll actually create a button until I create a row of buttons with objects of the letter A. If it contains a different letter, say B, I'll create a different row of buttons below the letter A row of buttons.
It will look like this:
[A1] [A2] [A3]
[B1] [B2] [B3]
[C1] [C2] [C3]
I'm thinking of doing a fast enumeration like this:
for (NSString *string in myArray)
{
if (// string has letter A)
{
Add string to array of A
}
else if (// string has letter B)
{
Add string to array of B
}
else if (// string has letter C)
{
Add string to array of C
}
}
But I'm not sure if I'm doing it right and fast.
This kind of approach might help indirectly. I'm not entirely sure what is being asked, so make of this what you will.
If you want to gather up by prefix, build an NSMutableDictionary whose keys will be #"A", #"B", ... and values are instances of NSMutableArray. For each string in your myArray, take it's prefix as the key to look up the array value in the dictionary, and add.
Something along the following lines:
NSArray *myArray = #[#"A1", #"A2", #"A3", #"B1", #"B2", #"B3", #"C1", #"C2", #"C3"];
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
for (NSString *s in myArray) {
if ([s length] < 1) {
continue;
}
NSString *key = [s substringToIndex:1];
if (![dict objectForKey:key]) {
[dict setObject:[NSMutableArray array] forKey:key];
}
NSMutableArray *bucket = [dict objectForKey:key];
[bucket addObject:s];
}
This kind of approach, which again may not directly answer your question, might prove instructive. It also has the advantage of being extensible - no need for yet another if clause.
Edit: The output of 'po dict' above in the console reads
(lldb) po dict
$2 = 0x0a33e660 {
A = (
A1,
A2,
A3
);
B = (
B1,
B2,
B3
);
C = (
C1,
C2,
C3
);
}
Find the character in string by using NSRange and do ur stuff. Like this
Try :
for (NSString *string in myArray)
{
if ([string rangeOfString:#"A"].location != NSNotFound)//Contains "A"
{
Add string to array of A
}
else if ([string rangeOfString:#"B"].location != NSNotFound)//Contains "B"
{
Add string to array of B
}
else if ([string rangeOfString:#"C"].location != NSNotFound)//Contains "C"
{
Add string to array of C
}
}
ope this helps u.

Finding minimum and maximum values in a nested NSDictionary

I have a Person NSDictionary, whose key is the Name of the person, and the object is an NSDictionary with two keys: his nickname (NSString) and his age (NSNumber).
I would like to end up with the Person dictionary sorted by the ascending order of their age, so that I could get the name of the youngest and the oldest person.
What is the best way to do it?
Thanks!
There are a few convenience methods defined in NSDictionary to sort items by values and get back the sorted keys.
See docs,
keysSortedByValueUsingComparator:
keysSortedByValueUsingSelector:
keysSortedByValueWithOptions:usingComparator:
I'm guessing you're using the modern Objective-C syntax and the age is actually represented as numbers. Here's how it looks:
[people keysSortedByValueUsingComparator:(NSDictionary *firstPerson, NSDictionary *secondPerson) {
return [firstPerson[#"age"] compare:secondPerson[#"age"]];
}];
Some languages offer sorted dictionaries, but the standard NSDictionary is inherently unsorted. You can get all the keys, sort the key array and then walk over the dictionary according to the sorted keys. (NSDictionary has several convenience methods for this use case that I didn’t know about, see Anurag’s answer.)
Your case is a bit more complex, one way to solve it is to introduce a temporary dictionary mapping ages to names. But if you’re only after the minimum and maximum ages, just iterate over all persons and keep track of the maximum & minimum ages and names:
NSString *oldestName = nil;
float maxAge = -1;
for (NSString *name in [persons allKeys]) {
NSDictionary *info = persons[name];
float age = [info[#"age"] floatValue];
if (age > maxAge) {
oldestName = info[#"nick"];
maxAge = age;
}
}
And if we get back to the idea of sorting the dictionary, this could work:
NSArray *peopleByAge = [people keysSortedByValueUsingComparator:^(id a, id b) {
// Again, see Anurag’s answer for a more concise
// solution using the compare: method on NSNumbers.
float ageA = [a objectForKey:#"age"];
float ageB = [b objectForKey:#"age"];
return (ageA > ageB) ? NSOrderedDescending
: (ageB > ageA) ? NSOrderedAscending
: NSOrderedSame;
}];
As #Zoul said the standard NSDictionary is unsorted.
To sort it you can use an array, and I do things like that
//the dictionary is called dict : in my case it is loaded from a plist file
NSDictionary *dict = [[NSDictionary alloc] initWithContentsOfFile:plistPath];
//make a dicoArray that is sorted so the results are sorted
NSArray *dicoArray = [[dict allKeys] sortedArrayUsingComparator:^(id firstObject, id secondObject) {
return [((NSString *)firstObject) compare:((NSString *)secondObject) options:NSNumericSearch];
}];
check the help for all the sort options. In the presented case the dictionary is sorted with keys treated as numeric value (which was the case for me).
If you need to sort another way the list of sort possibilities is
enum {
NSCaseInsensitiveSearch = 1,
NSLiteralSearch = 2,
NSBackwardsSearch = 4,
NSAnchoredSearch = 8,
NSNumericSearch = 64,
NSDiacriticInsensitiveSearch = 128,
NSWidthInsensitiveSearch = 256,
NSForcedOrderingSearch = 512,
NSRegularExpressionSearch = 1024
};
In iOS 9.2
// Dictionary of NSNumbers
NSDictionary * phoneNumbersDict = #{#"400-234-090":67,#"701-080-080":150};
// In Ascending Order
NSArray * keysArraySortedByValue = [phoneNumbersDict keysSortedByValueUsingComparator:^NSComparisonResult(id _Nonnull obj1, id _Nonnull obj2) {
return [obj1 compare:obj2];
}];
// In Descending Order
NSArray * keysArraySortedByValue = [phoneNumbersDict keysSortedByValueUsingComparator:^NSComparisonResult(id _Nonnull obj1, id _Nonnull obj2) {
return [obj2 compare:obj1];
}];
Here is the enum for NSComparisonResults.
enum {
NSOrderedAscending = -1,
NSOrderedSame,
NSOrderedDescending
};
typedef NSInteger NSComparisonResult;
Look at the NSDictionary's method that returns keys sorted by a selector. There are more than one such method. You get an array of sorted keys, then access the first and last and have your youngest and oldest person.

Why does changing a mutable array contained in a dictionary not require updating the dictionary?

I was trying a piece of code from CS193P course (Objective-C). I noticed something in the way that the compiler works. An NSMutableArray called photos was added to an NSMutableDictionary, photosByPhotographer. Later on, a change was made to photos without any changes to photosByPhotographer. When I logged photosByPhotographer, the change was automatically applied to it and it did not need any extra lines of code!
I wonder how the compiler makes this work? Any materials to read from?
The code is as follows:
- (void)updatePhotosByPhotographer
{
NSMutableDictionary *photosByPhotographer = [NSMutableDictionary dictionary];
for (NSDictionary *photo in self.photos) {
NSString *photographer = [photo objectForKey:FLICKR_PHOTO_OWNER];
NSMutableArray *photos = [photosByPhotographer objectForKey:photographer];
if (!photos) {
photos = [NSMutableArray array];
[photosByPhotographer setObject:photos forKey:photographer];
NSLog(#"photosByPhotographer in if: %#", photosByPhotographer);
}
[photos addObject:photo];
NSLog(#"photosByPhotographer after if: %#", photosByPhotographer);
}
self.photosByPhotographer = photosByPhotographer;
}
The NSLog() result is as follows:
2012-07-20 20:05:57.618 Shutterbug[453:f803] photosByPhotographer in if: {
Dowbiggin = (
);
}
2012-07-20 20:05:57.620 Shutterbug[453:f803] photosByPhotographer after if: {
Dowbiggin = (
{
accuracy = 16;
context = 0;
dateupload = 1342836026;
description = {
"_content" = "";
};
farm = 9;
"geo_is_contact" = 0;
"geo_is_family" = 0;
"geo_is_friend" = 0;
"geo_is_public" = 1;
id = 7612787270;
isfamily = 0;
isfriend = 0;
ispublic = 1;
latitude = "37.307085";
longitude = "-121.900395";
originalformat = jpg;
originalsecret = 052e70d412;
owner = "22751315#N05";
ownername = Dowbiggin;
"place_id" = cils8sJUV7MeXHwt9A;
secret = 4437007c99;
server = 8161;
tags = "square squareformat iphoneography instagramapp uploaded:by=instagram foursquare:venue=49f13597f964a5209c691fe3";
title = "My little goofball";
woeid = 55971033;
}
);
}
That's because in Cocoa, you are using objects and pass by reference.
Imagine this code:
NSMutableArray *a, *b;
a = [NSMutableArray new];
[a addObject:#"A"]; // a contains #"A"
b = a; // b is assigned to the same object
[b addObject:#"B"]; // a and b contain #"A", #"B"
NSLog(#"a = %p and b = %p", a, b); // same values
The variables a and b point to the same object. You can also see that by comparing the pointer values.
However, if we do the following:
NSMutableArray *a, *b;
a = [NSMutableArray new];
[a addObject:#"A"]; // a contains #"A"
b = [[a mutableCopy] autorelease]; // b is assigned to a COPY of the object
[b addObject:#"B"]; // b contains #"A", #"B", while a still contains #"A"
NSLog(#"a = %p and b = %p", a, b); // NOT the same values
b is assigned to a copy of a (not the original), so b points to an other object. You can check by comparing the addresses of the objects.
The photos arrays is stored by reference in the NSDictionary, not as a copy. Therefore, if you change the underlying array, you will see that when you access the dictionary.
This is why it can be dangerous to provide some mutable types by reference instead of storing copies of them.
You need to understand how pointers and references work. Basically rather than variables in your code being actual full structures and objects, generally they are references or pointers to those structures. You can visualise the concept in a number of ways, but perhaps one that's useful is to think of a variable such as:
NSDictionary *myDict;
being really just a number which is the memory address of the myDict object. Here's a visualisation of how it works:
Your NSDictionary reference points to an object in memory which itself holds multiple references to other objects, which can be changed without affecting the dictionary itself. In this example I've shown an NSArray having a new object added to it. The reference to the array from the dictionary remains the same. There is only ever one instance of the array and the objects in it at any time.
When you call NSLog on an NSDictionary object then its method description is called.
In the implementation of the method description, NSDictionary is calling the description method of each value (object) of all its keys.
So when a value (object) changes so does the output of its description method change.
That is why it is reflected when calling NSLog on an NSDictionary object again.

Sort 4 ints, smallest to biggest

Suppose I have 4 integers.
int a = 4;
int b = 2;
int c = 4;
int d = 1;
How can I sort these integers from smallest to biggest. The output needs to be something like this: d, b, a, c Most methods of sorting only give me the value of the sorted integer. I need to know the name.
Edit: Well, I'm writing an AI algorithm. I have 4 ints that store direction priority. (If the AI comes into a wall, it chooses the next best direction). So, I need to find the lowest int, and if the AI can't move that way, I choose the second to lowest etc.
There appears to be some confusion here; in your example a is not the "name" for the value 4, it is the name of an integer variable which currently contains 4. In other words "a" is not part of the data of your program.
What I assume you mean is you have name/value pairs which you wish to sort using the value as key. A common way to do this is to define a type for your pair, create a collection, and sort the collection.
In plain C you can declare:
typedef struct
{
char *name;
int value;
} MyPair;
You can create an array of these and sort it using standard C functions for array sorting, using just the value field as the key.
In Objective-C you can declare a class for your pair:
#interface MyPair : NSObject
{
NSString *name;
int value;
}
// methods/properties
#end
You can create an NSMutableArray of instances of MyPair and then sort the array, again you just use the value property (or instance variable) when doing the comparisons for the sort algorithm.
There are other variations of course. Once sorted you can iterate through the sorted array and display the name field/property.
Here is an objective-c approach. Unfortunately, you will not have the fun of writing the AI portion, the sorting is built into the libraries already.
int north = 1, south = 3, east = 2, west =4;
NSDictionary * nDict = [NSDictionary dictionaryWithObjectsAndKeys:#"north", #"name", [NSNumber numberWithInt:north], #"value", nil];
NSDictionary * sDict = [NSDictionary dictionaryWithObjectsAndKeys:#"south", #"name", [NSNumber numberWithInt:south], #"value", nil];
NSDictionary * eDict = [NSDictionary dictionaryWithObjectsAndKeys:#"east", #"name", [NSNumber numberWithInt:east], #"value", nil];
NSDictionary * wDict = [NSDictionary dictionaryWithObjectsAndKeys:#"west", #"name", [NSNumber numberWithInt:west], #"value", nil];
NSArray * toBeSorted = [NSArray arrayWithObjects:nDict,sDict,eDict,wDict,nil];
NSArray * sortDescriptors = [NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:#"value" ascending:NO]];
NSArray * sorted = [toBeSorted sortedArrayUsingDescriptors:sortDescriptors];
NSLog(#"sorted %#", sorted);
Output
2012-01-23 19:50:21.079 TestEnvironment[19792:207] sorted (
{
name = west;
value = 4;
},
{
name = south;
value = 3;
},
{
name = east;
value = 2;
},
{
name = north;
value = 1;
}
)
Now you can check the highest priority by
NSString * highestPriority = [[sorted objectAtIndex:0] objectForKey:#"name"];
Now you have some classes you can look up (NSArray, NSDictionary, NSSortDescriptor, NSNumber)
You've tagged this Objective-C, but you haven't written anything that suggests using Objective-C. If you want to use Objective-C, I'd put the elements into an NSMutableArray (they'll need to be converted to NSNumbers to do that), and have the array sort them, as seen here.
If you just want to put them into a straight C array, you could sort them using heapsort (), qsort(), or mergesort().