I am having a bit of trouble navigating around an NSArray.
My array:
Element[0] = "ElementA"
Element[1] = "ElementA"
Element[2] = "ElementA"
Element[3] = "ElementA"
Element[4] = "ElementB"
Element[5] = "ElementC"
Are there any methods in Objective-C that will help me find the "median" element? In this case, the "median" would be "ElementA", or the value that occurs the maximum number of times.
In C# this would be a single call, but I can't find an equivalent in Objective-C.
Many thanks,
Brett
Here's how I'd do it:
NSArray * elements = ...; //your array of elements:
NSCountedSet * counts = [NSCountedSet setWithArray:elements]:
id modeObject = nil;
NSUInteger modeCount = 0;
for (id element in counts) {
if ([counts countForObject:element] > modeCount) {
modeCount = [counts countForObject:element];
modeObject = element;
}
}
NSLog(#"element with highest frequency: %#", modeObject);
An NSCountedSet is an NSMutableSet that also remembers how many times its elements have been added to the array.
Wrote this just for you :)
- (NSString *) findModeString: (NSArray *) array {
NSMutableDictionary *stats = [[NSMutableDictionary alloc] init];
for(NSString *str in array) {
if(![stats objectForKey:str]) {
[stats setObject: [NSNumber numberWithInt:1] forKey:str];
} else {
[stats setObject: [NSNumber numberWithInt:[[stats objectForKey:str] intValue] + 1] forKey:str];
}
}
NSInteger maxOccurrences = 0;
NSString *max;
for(NSString *key in stats) {
if([[stats objectForKey:key] intValue] > maxOccurrences) {
max = key;
maxOccurrences = [[stats objectForKey:key] intValue];
}
}
[stats release];
return max;
}
EDIT: Although my solution works, you should upvote/accept #Dave DeLong's answer, it is much much better.
Couldn't you just use:
[myarray length] /2
Related
I have a NSArray which contain n number of NSDictionary sampleArray =
(
{
0 = 0;
1 = 0;
},
{
0 = 86400;
1 = 2;
},
{
0 = 172800;
1 = 4;
},
{
0 = 259200;
1 = 5;
}
)
Now I need to fetch the NSArray for objectForKey 0 [sampleArray objectForKey:[NSNumber numberWithInt:0]], my result NSArray should be like
(0,86400,172800,259200) but I am unable to fetch the result and the app crashes.
Normally for NSDictionary, if key value is set using NSString valueForKey the above operation is performed successfully but if key value is set using an object like NSNumber objectForKey I am unable to perform the operation.
Please help me to get a solution, any suggestion would be appreciated!!
A very straight forward way if your keys are NSNumber objects:
NSMutableArray *result = [[NSMutableArray alloc] init];
for (NSDictionary *d in a) {
if (d[#0]) {
[result addObject:d[#0]];
}
}
THIS doesnt work - im sorry: I didnt see you didnt have Strings as keys + I didnt know KVC only works with strings
I leave it though
what you are looking for is
NSArray *zeros = [mainArray valueForKey:#"0"];
it gets "0" from each dict in array
What you have do is
NSMutableArray *arrResult = [[NSMutableArray alloc]init];
for(int i=0;i<[sampleArray count];i++)
{
NSString *strValue = [[sampleArray objectAtIndex:i] valueforkey:#"0"];
[ arrResult addobject:strValue];
}
let me know it is working or not!!!!
Happy coding!!!!!
here you can try NSArray *tempArray
for (NSDictionary *list in tempArray)
{
[firstArray addObject:[list objectForKey:#"0"];
[secondArray addObject:[list objectForKey:#"1"];
}
I have an array which contains strings like frame_10#3x.png , frame_5#3x.png,frame_19#3x.png etc.
So I want to sort this array according to the number after the underscore i.e. the correct sequence will be frame_5#3x.png,frame_10#3x.png,frame_19#3x.png.
I tried to use the following method but no result:
NSInteger firstNumSort(id str1, id str2, void *context) {
int num1 = [str1 integerValue];
int num2 = [str2 integerValue];
if (num1 < num2)
return NSOrderedAscending;
else if (num1 > num2)
return NSOrderedDescending;
return NSOrderedSame;
}
Please suggest how to do this sorting for array.
NSArray *sry_img = [[NSArray alloc] initWithObjects:#"frame_18#3x.png",#"frame_17#3x.png",#"frame_1222#3x.png",#"frame_10#3x.png",#"frame_3#3x.png",#"frame_4#3x.png",#"frame_4#3x.png",#"frame_1#3x.png",#"frame_4#3x.png",#"frame_4#3x.png",nil];
NSArray *sortedStrings = [sry_img sortedArrayUsingSelector:#selector(localizedStandardCompare:)];
NSLog(#"%#",sortedStrings);
Enjy .......
But
localizedStandardCompare:, added in 10.6, should be used whenever file names or other strings are presented in lists and tables where Finder-like sorting is appropriate. The exact behavior of this method may be tweaked in future releases, and will be different under different localizations, so clients should not depend on the exact sorting order of the strings.
you want to do something like:
NSArray *components1 = [str1 componentsSeparatedByString:#"_"];
NSArray *components2 = [str2 componentsSeparatedByString:#"_"];
NSString *number1String = [components1 objectAtIndex:([components1 count] - 1])];
NSString *number2String = [components2 objectAtIndex:([components2 count] - 1])];
return [number1String compare:number2String];
I am not sure if my solution is the best possible approach but it can solve your problem for the time being :) .
1) First I have written a function to get the numbers before # character in your string and then I implemented simple SELECTION SORT algo to sort the array using this functions.
- (NSString*)getSubStringForString:(NSString*)value {
// First we will cut the frame_ string
NSMutableString *trimmedString = [NSMutableString stringWithString:[value substringWithRange:NSMakeRange(6, [value length]-6)]];
// New String to contain the numbers
NSMutableString *newString = [[NSMutableString alloc] init];
for (int i = 0; i < [trimmedString length] ; i++) {
NSString *singleChar = [trimmedString substringWithRange:NSMakeRange(i, 1)];
if (![singleChar isEqualToString:#"#"]) {
[newString appendString:singleChar];
} else {
break;
}
}
return newString;
}
This is the selection Implementation of the algo for sorting. The main logic is in the for loop. You can copy the code in viewDidLoad method to test.
NSMutableArray *array = [[NSMutableArray alloc] initWithObjects:#"frame_10#3x.png",#"frame_5#3x.png",
#"frame_3#3x.png", #"frame_19#3x.png",
nil];
NSLog(#"Values before Sort: %#", array);
int iPos;
int iMin;
for (iPos = 0; iPos < [array count]; iPos++)
{
iMin = iPos;
for (int i = iPos+1; i < [array count]; i++)
{
if ([[self getSubStringForString:[array objectAtIndex:i]] intValue] >
[[self getSubStringForString:[array objectAtIndex:iMin]] intValue]) {
iMin = i;
}
}
if ( iMin != iPos )
{
NSString *tempValue = [array objectAtIndex:iPos];
[array replaceObjectAtIndex:iPos withObject:[array objectAtIndex:iMin]];
[array replaceObjectAtIndex:iMin withObject:tempValue];
}
}
NSLog(#"Sorted Values: %#", array);
I hope that it can atleast keep you going. :)
You can try this-
NSString *str1 = [[[[str1 componentsSeparatedByString:#"frame_"] objectAtIndex:1] componentsSeparatedByString:#"#3x.png"] objectAtIndex:0];
int num1 = [str1 integerValue];
NSMutableArray*array = [[NSMutableArray alloc]init];
NSArray*Somearray = [NSArray arrayWithObjects:1st Object,2ndObject,3rd Object,4th object,5th Object,nil];
In the above array 1st Object,2ndObject,3rd Object,4th object,5th Object having val,content,conclusion in each index.
for(int i=0;i<[Somearray count];i++)
{
______________
Here the code is there to give each index ,that is having val,content,conclusion ..
After that val,content,conclusion in each index will be add to Dict..
____________
NSDictionary *Dict = [NSDictionary dictionaryWithObjectsAndKeys:val,#"val",content,#"content",conclusion,#"conclusion",nil];
//Each time adding dictionary into array;
[array addObject:Dict];
}
The above Dictionary is in for loop and the keyvalue pairs will be add 5 times(Somearray Count).Now array is having in
array = [{val="1.1 this is first one",content="This is the content of 0th index",conclusion="this is the conclusion of 0th index"},{val="1.2 this is first one",content="This is the content of 1st index",conclusion="this is the conclusion of 1st index"},____,____,______,{val="1.5 this is first one",content="This is the content of 4th index",conclusion="this is the conclusion of 4th index"},nil];
Now i am having NSString*string = #"1.5";
Now i need the index where val is having 1.5 in it.How to send the str in to array to find the the index.
Can anyone share the code please.
Thanks in advance.
Use method indexOfObject
int inx= [array indexOfObject:#"1.5"];
For Find index particular key value.
int inx;
for (int i=0; i<[array count]; i++) {
if ([[[array objectAtIndex:i] allKeys] containsObject:#"val"]) {
inx=i;
break;
}
}
The method you are looking for is -[NSArray indexOfObjectPassingTest:]. You would use it like this:
NSUInteger i = [array indexOfObjectPassingTest:^(id obj, NSUInteger idx, BOOL *stop) {
return [[id objectForKey:#"val"] rangeOfString:#"1.5"].location != NSNotFound;
}];
If you just want to check that val starts with "1.5" you would use hasPrefix: instead.
Try this -
NSArray *valArray = [array valueForKey:#"val"];
int index = [valArray indexOfObject:#"1.5"];
Appended answer given by Mandeep, to show you the magic of key value coding ;)
NSUInteger idx = UINT_MAX;
NSCharacterSet* spaceSet = [NSCharacterSet whitespaceCharacterSet];
for(int i=0,i_l=[Yourarray count];i<i_l;i++) {
NSString* s_prime = [[Yourarray objectAtIndex:i] valueForKey:#"val"];
if ([s_prime length] < 4) {
continue;
}
NSString *subString = [[s_prime substringToIndex:4] stringByTrimmingCharactersInSet:spaceSet];
// NSLog(#"index %#",s);
if ([subString isEqualToString:secretNumber]){
idx = i;
break;
}
}
if (idx != UINT_MAX) {
// NSLog(#"Found at index: %d",idx);
} else {
// NSLog(#"Not found");
}
I need to sort a NSDictionary of dictionaries. It looks like:
{//dictionary
RU = "110.1"; //key and value
SG = "150.2"; //key and value
US = "50.3"; //key and value
}
Result need to be like:
{//dictionary
SG = "150.2"; //key and value
RU = "110.1"; //key and value
US = "50.3"; //key and value
}
I am trying this:
#implementation NSMutableDictionary (sorting)
-(NSMutableDictionary*)sortDictionary
{
NSArray *allKeys = [self allKeys];
NSMutableArray *allValues = [NSMutableArray array];
NSMutableArray *sortValues= [NSMutableArray array];
NSMutableArray *sortKeys= [NSMutableArray array];
for(int i=0;i<[[self allValues] count];i++)
{
[allValues addObject:[NSNumber numberWithFloat:[[[self allValues] objectAtIndex:i] floatValue]]];
}
[sortValues addObjectsFromArray:allValues];
[sortKeys addObjectsFromArray:[self allKeys]];
[sortValues sortUsingDescriptors:[NSArray arrayWithObject:[[[NSSortDescriptor alloc] initWithKey:#"floatValue" ascending:NO] autorelease]]];
for(int i=0;i<[sortValues count];i++)
{
[sortKeys replaceObjectAtIndex:i withObject:[allKeys objectAtIndex:[allValues indexOfObject:[sortValues objectAtIndex:i]]]];
[allValues replaceObjectAtIndex:[allValues indexOfObject:[sortValues objectAtIndex:i]] withObject:[NSNull null]];
}
NSLog(#"%#", sortKeys);
NSLog(#"%#", sortValues);
NSLog(#"%#", [NSMutableDictionary dictionaryWithObjects:sortValues forKeys:sortKeys]);
return [NSMutableDictionary dictionaryWithObjects:sortValues forKeys:sortKeys];
}
#end
This is the result of NSLog:
1)
{
SG,
RU,
US
}
2)
{
150.2,
110.1,
50.3
}
3)
{
RU = "110.1";
SG = "150.2";
US = "50.3";
}
Why is this happening? Can you help me with this problem?
NSDictionary are unsorted by nature. The order of the objects as retrieved by allKeys and allValues will always be undetermined. Even if you reverse engineer the order it may still change in the next system update.
There is however more powerful alternatives to allKeys that are used to retrieve the keys in a defined and predictable order:
keysSortedByValueUsingSelector: - Useful for sorting in ascending order according to the compare: method of the value objects.
keysSortedByValueUsingComparator: - New in iOS 4, use a block to do the sort inline.
WOW. Thanx, PeyloW! It's what i needed! I also find this code and it helps me to reorder results:
#implementation NSString (numericComparison)
- (NSComparisonResult) floatCompare:(NSString *) other
{
float myValue = [self floatValue];
float otherValue = [other floatValue];
if (myValue == otherValue) return NSOrderedSame;
return (myValue < otherValue ? NSOrderedAscending : NSOrderedDescending);
}
- (NSComparisonResult) intCompare:(NSString *) other
{
int myValue = [self intValue];
int otherValue = [other intValue];
if (myValue == otherValue) return NSOrderedSame;
return (myValue < otherValue ? NSOrderedAscending : NSOrderedDescending);
}
#end
a NSDictionary is not ordened, so it doens't matter in what order you construct a NSDIctionary.
a NSArray is ordened. If you want to have the NSDictionary ordened in memory, you should somehow make a NSArray of key value pairs. You can also return two NSArrays with corresponding indeces.
If you only want to iterate over the elements way, you can iterate over a sorted array of keys (this is what koregan suggests).
First off I am very new to Objective C and iPhone programming. Now that that is out of the way. I have read through most of the Apple documentation on this and some third party manuals.
I guess I just want to know if I'm going about this the correct way ...
- (NSMutableArray *)makeModel {
NSString *api = #"http://www.mycoolnewssite.com/api/v1";
NSArray *namesArray = [NSArray arrayWithObjects:#"News", #"Sports", #"Entertainment", #"Business", #"Features", nil];
NSArray *urlsArray = [NSArray arrayWithObjects:
[NSString stringWithFormat:#"%#/news/news/25/stories.json", api],
[NSString stringWithFormat:#"%#/news/sports/25/stories.json", api],
[NSString stringWithFormat:#"%#/news/entertainment/25/stories.json", api],
[NSString stringWithFormat:#"%#/news/business/25/stories.json", api],
[NSString stringWithFormat:#"%#/news/features/25/stories.json", api], nil];
NSMutableArray *result = [NSMutableArray array];
for (int i = 0; i < [namesArray count]; i++) {
NSMutableDictionary *objectDict = [NSMutableDictionary dictionary];
NSString *name = (NSString *)[namesArray objectAtIndex:i];
NSString *url = (NSString *)[urlsArray objectAtIndex:i];
[objectDict setObject:name forKey:#"NAME"];
[objectDict setObject:url forKey:#"URL"];
[objectDict setObject:#"NO" forKey:#"HASSTORIES"];
[result addObject:objectDict];
}
return result;
}
The output of the result is ...
(
{
HASSTORIES = NO;
NAME = News;
URL = "http://www.mycoolnewssite.com/api/v1/news/news/25/stories.json";
},
{
HASSTORIES = NO;
NAME = Sports;
URL = "http://www.mycoolnewssite.com/api/v1/news/sports/25/stories.json";
},
{
HASSTORIES = NO;
NAME = Entertainment;
URL = "http://www.mycoolnewssite.com/api/v1/news/entertainment/25/stories.json";
},
{
HASSTORIES = NO;
NAME = Business;
URL = "http://www.mycoolnewssite.com/api/v1/news/business/25/stories.json";
},
{
HASSTORIES = NO;
NAME = Features;
URL = "http://www.mycoolnewssite.com/api/v1/news/features/25/stories.json";
}
)
Any insight would be appreciated ;-)
It looks fine. There can be some minor improvements if you care.
1.
[NSString stringWithFormat:#"%#/news/news/25/stories.json", api]
can be replaced by
[api stringByAppendingString:#"/news/news/25/stories.json"]
if there's no chance the api appears in the middle or accepts other arguments.
2.
NSString *name = (NSString *)[namesArray objectAtIndex:i];
NSString *url = (NSString *)[urlsArray objectAtIndex:i];
The explicit cast is unnecessary. An id can be implicitly casted to and from other ObjC objects.
3.
You could use a convenient method -dictionaryWithObjectsAndKeys: to construct the dictionary in one-shot, so you don't need a temperary dictionary:
[result addObject:[NSMutableDictionary dictionaryWithObjectsAndKeys:
name, #"NAME",
url, #"URL",
#"NO", #"HASSTORIES", nil]];
4. (optional)
This transform is not useful if the function is not a hot spot.
Since the arrays are only used locally, it's more efficient to use a C array.
static const int arraySize = 5;
NSString* namesCArray[] = {#"News", #"Sports", #"Entertainment", #"Business", #"Features"};
NSString* urlsCArray[arraySize];
urlsArray[0] = [api stringByAppendingString:#"/news/news/25/stories.json"];
...
for (int i = 0; i < arraySize; ++ i) {
...
NSString* name = namesCArray[i];
NSString* url = urlsCArray[i];
...
}
this removes the repeated -count and -objectAtIndex: calls which is very slow compared with direct element access.
5. (optional)
This transform is not useful if the array is short.
You could use fast-enumeration to loop over an ObjC container:
int i = 0;
for (NSString* name in namesArray) {
NSString* url = [urlsArray objectAtIndex:i];
...
++ i;
}
6.
Usually we use [NSNumber numberWithBool:NO] to represent a boxed true/false value, instead of a string #"NO". NSNumber is also used a lot whenever a primitive number (int, float, etc.) cannot be used (e.g. to be stored in an NSArray). I don't know if your API explicitly requires a string NO, so it may not unsuitable for you.