How to find the average of a group of NSNumbers from NSMutableArray? - ios

I have an NSMutableArray of NSNumbers that I have created using this code.
if (countMArray == nil) {
countMArray = [[NSMutableArray alloc] init];
}
if ([countMArray count] == 10) {
[countMArray removeObjectAtIndex:0];
}
NSNumber *currentX = [NSNumber numberWithDouble:x];
[countMArray addObject:currentX];
NSLog(#"%#", countMArray);
this is how my array looks.
2014-05-02 20:34:35.065 MotionGraphs[3721:60b] (
"0.0292816162109375",
"0.0315704345703125",
"0.03271484375",
"0.030517578125",
"0.03094482421875",
"0.0302886962890625",
"0.03192138671875",
"0.0306396484375",
"0.03094482421875",
"0.02874755859375"
)
I would like to find the average of the 10 numbers, I understand the mathematics behind it are simple: add all the values then divide by 10. However, I would like to know the best way to attempt this.

If you simply wanted to average all the countMArray in the numbers array, you could use KVC collection operator:
NSNumber *average = [countMArray valueForKeyPath:#"#avg.self"];

You should use if array contains NSNumber
NSNumber *average = [countMArray valueForKeyPath:#"#avg.doubleValue"];
But you are having NSStrings, so use this below method
-(double)avgOfArray:(NSArray*)array{
double total=0.0;
for (NSString *aString in array) {
total+=[aString doubleValue];
}
return ([array count]>0)?(total/[array count]):total;
}

Related

How to convert elements of NSMutableArray (NString) to NSNumber and add them up?

Ok so I have NsMutable array with Strings which are in format:
32,45,54,5550 etc.
What is the easiest way to convert all these strings to nsnumber and also get the sum of entire array.
You can use the KVC collection operator #sum to get the summation of all number strings stored in an array
NSArray *numberStrings = #[#"32",#"45",#"54",#"5550"];
NSNumber* sum = [numberStrings valueForKeyPath: #"#sum.self"];
NSLog(#"%#", sum);
output: 5681
For simple strings it works. But caution: in localization there might be traps. There-for I would still suggest to use a NSNumberFormatter to create real NSNumber objects, store them in another array and use #sum on that.
Thanks Bryan Chen for make me test.
To raise the awareness for problems that might lie in localization, I want to share this experiment with you:
In German we use , to separate the decimal digits, where as we use the . to group long numbers in thousands.
So if the numberString array might be filled with german formatted numbers, it might look like #[#"32,5", #"45", #"54", #"5.550,00"]. The sum of this is 5681.5, but if we do not alter the code, it will not fail, but worse — miscalculate: 136.55. It just ignored everything past a comma and treated . as decimal separator.
Lets use a NSNumberFormatter to fix it:
My system is set to german locale
NSNumberFormatter *nf = [[NSNumberFormatter alloc] init];
nf.locale = [NSLocale currentLocale];
[nf setGroupingSize:3];
nf.usesGroupingSeparator= YES;
NSArray *numberStrings = #[#"32,5", #"45", #"54", #"5.550,00"];
NSMutableArray *numbers = [#[] mutableCopy];
for (NSString *s in numberStrings) {
NSNumber *n = [nf numberFromString:s];
[numbers addObject:n];
}
NSNumber* sum = [numbers valueForKeyPath: #"#sum.self"];
NSLog(#"%#", sum);
it prints correctly 5681.5.
NSArray *array = #[ #"1,2", #"3,4" ];
NSUInteger sum = 0;
for (NSString *str in array)
{
for (NSString *num in [str componentsSeparatedByString:#","])
{
sum += [num intValue];
}
}
or
NSArray *array = #[ #"1", #"3" ];
NSUInteger sum = 0;
for (NSString *num in array)
{
sum += [num intValue];
}

how to group array of nsdictionary according to the value inside the element

I have array of dictionary that needs to be grouped according to PO which is part of the element and also get the total of quantityOrdered according to the same PO.
The PO is dynamic it means it can be any value that needs to be filtered and compute the quantityOrderd accordingly.
Please help.
{
PO = PO2;
QuantityReceived = 1;
},
{
PO = PO1;
QuantityReceived = 3;
},
{
PO = PO1;
QuantityReceived = 3;
},
{
PO = PO3;
QuantityReceived = 2;
},
{
PO = PO2;
QuantityReceived = 2;
},
{
PO = PO3;
QuantityReceived = 4;
},
{
PO = PO1;
QuantityReceived = 1;
},
Apology for the confusion or incomplete question but i need to create a new array of dictionary with similar like this :
{
PO = PO1;
TotalQuanityReceived=7;
LineItems=3;
},
{
PO = PO2;
TotalQuanityReceived=3;
LineItems=2;
},
{
PO = PO3;
TotalQuanityReceived=6;
LineItems=2;
},
i updated my example and make it easy to read.
- (NSArray *)whatever:(NSArray *)dictionaries
{
NSMutableArray *results = [[NSMutableArray alloc] init];
NSMutableDictionary *resultsByPO = [[NSMutableDictionary alloc] init];
for (NSDictionary *dictionary in dictionaries) {
id po = [dictionary objectForKey:#"PO"];
NSMutableDictionary *result = [resultsByPO objectForKey:po];
if (result == nil) {
result = [[NSMutableDictionary alloc] init];
[resultsByPO setObject:result forKey:po];
[results addObject:result];
[result setObject:po forKey:#"PO"];
}
double total = [[result objectForKey:#"TotalQuantityReceived"] doubleValue];
total += [[dictionary objectForKey:#"QuantityOrdered"] doubleValue];
int count = 1 + [[result objectForKey:#"Count"] intValue];
[result setObject:#(total) forKey:#"TotalQuantityReceived"];
[result setObject:#(count) forKey:#"Count"];
}
return results;
}
More pain will come with PO values not conforming to NSCopying.
You can do it the clever way with KVC or the stupid easy way. Let's do it the stupid easy way!
Make an empty NSMutableDictionary. Let's call it dict.
Cycle through your array of dictionaries. For each dictionary:
Fetch its PO. Call that value thisPO.
Fetch dict[thisPO]. Was it nil?
a. Yes. Okay, so this particular PO has not yet been encountered. Set dict[thisPO] to this dictionary's quantity received (as an NSNumber).
b. No. Turn that value into an integer, add this dictionary's quantity received, and set the total back into dict[thisPO] (as an NSNumber).
Done! The result is not quite what you asked for; the result looks like this:
{
PO1 = 100;
PO2 = 120;
...
}
But now, you see, the work of totalling is done and it is easy to transform that into an array of dictionaries if that is what you want.
Not 100% sure if this is what you are saying or not, but to sort an array of dictionaries based on one of the elements it would look something like this.
NSDictionary *d1 = [[NSDictionary alloc] initWithObjectsAndKeys:
[NSNumber numberWithDouble:100],#"PO",
[NSNumber numberWithDouble:0], #"Category",
nil];
NSDictionary *d2 = [[NSDictionary alloc] initWithObjectsAndKeys:
[NSNumber numberWithDouble:50],#"PO",
[NSNumber numberWithDouble:90], #"Category",
nil];
NSArray *unsorted = #[d1, d2];
NSArray *sortedArray;
sortedArray = [unsorted sortedArrayUsingComparator:^NSComparisonResult(id a, id b) {
NSDictionary *first = (NSDictionary*)a;
NSDictionary *second = (NSDictionary*)b;
NSNumber *firstPO = [first objectForKey:#"PO"];
NSNumber *secondPO = [second objectForKey:#"PO"];
return [firstPO compare:secondPO];
}];
NSLog(#"unsorted = %#", unsorted);
NSLog(#"sorted = %#", sortedArray);
I wasn't really sure what PO was, so I just used an NSNumber as an example. Look at this page for an overview of how you would compare a customer object. http://nshipster.com/nssortdescriptor/.
Then you can loop through the array, now in the correct order and build your next NSDictionary.

Calling arc4random several times and getting the same array set

I need a method to generate 4 numbers positioned randonly in an array. This method must be able to be called several times. The code that I tried below seems to be working.. except that everytime I call it, it generates the very same numbers sequence.
At my header file:
NSMutableSet * numberSet;
NSArray * numbers;
Code file:
numberSet = [NSMutableSet setWithCapacity:4];
[self placeRandomLine];
numbers = [numberSet allObjects];
... using the generated array
[self placeRandomLine];
numbers = [numberSet allObjects];
... using the generated array
[self placeRandomLine];
numbers = [numberSet allObjects];
... using the generated array
Random Method:
-(void)placeRandomLine
{
[numberSet removeAllObjects];
while ([numberSet count] < 4 ) {
NSNumber * randomNumber = [NSNumber numberWithInt:(arc4random() % 4)];
[numberSet addObject:randomNumber];
}
}
I am sure I am missing something here..
Thanks for your help!
Use an ordered set:
NSMutableOrderedSet *numberSet = [NSMutableOrderedSet new];
int setSize = 4;
while ([numberSet count] < setSize ) {
NSNumber * randomNumber = [NSNumber numberWithInt:arc4random_uniform(setSize)];
[numberSet addObject:randomNumber];
}
NSLog output:
numberSet: {(
2,
0,
1,
3
)}
Alternatively using an array or arbitrary numbers
Create an NSMutableArray with the four integers.
Create an empty NSMutableArray.
Use arc4random_uniform() to pick one of the numbers in the first array, remove it and place it in the second array.
Repeat for all four numbers.
The second array will have the four numbers in a random order.
Example:
NSMutableArray *a0 = [#[#3, #5, #4, #8] mutableCopy];
NSMutableArray *a1 = [NSMutableArray new];
while (a0.count) {
int randomIndex = arc4random_uniform(a0.count);
NSNumber *randomValue = a0[randomIndex];
[a1 addObject:randomValue];
[a0 removeObject:randomValue];
}
NSLog(#"a1: %#", a1);
NSLog output:
a1: (
8,
5,
3,
4
)
Alternatively using an ordered set
while ([numberSet count] < 4 ) will cause the loop to run until its elements are 0,1,2,3, because the set doesn't contain repeated elements.

How to sort an Array of signed numbers in iOS?

This may be a simple question, but i don't know the way of doing sorting of array of signed integer values.
My array before sorting,
pointsAry (-2,-7,-5,0,-3,2,-1,-4,1,3,-6)
After using
NSArray * sortedArray = [pointsAry sortedArrayUsingComparator:^(id str1, id str2){
return [(NSString *)str1 compare:(NSString *)str2 options:NSNumericSearch];
}];
Result
sortedArray : (-1,-2,-3,-4,-5,-6,-7,0,1,2,3)
for signed values the sortedArray format is not correct, so i need like
(-7,-6,-5,-4,-3,-2,-1,0,1,2,3)
How to sort like above format ? Thanks in advance.
The following comparator avoids the creation of temporary NSNumber objects:
NSArray *sortedArray = [pointsAry sortedArrayUsingComparator:^NSComparisonResult(NSString *str1, NSString *str2) {
return my_int_compare([str1 intValue], [str2 intValue]);
}];
where
static inline int my_int_compare(int x, int y) { return (x > y) - (x < y); }
is a helper function that compares two integers and returns -1, 0, or +1 (as required
for a comparator method), using the technique from
Is there a standard sign function (signum, sgn) in C/C++?.
Of course the problem only arises because the array contains NSString objects.
Using NSNumbers would be the better solution.
Using the NSNumericSearch option does not help because it does not treat the minus
sign as part of the number.
NSArray *sortedArray = [pointsAry sortedArrayUsingComparator:^(NSString *str1, NSString *str2){
return [#([str1 intValue]) compare:#([str2 intValue])];
}];
NSMutableArray *array = [[NSMutableArray alloc] initWithObjects:#"P3",#"P1",#"P4",#"P10", nil];
NSMutableArray *num=[[NSMutableArray alloc]init];
for(int i=0;i<array.count;i++)
{
NSString *str=array[i];
[num addObject: [str substringFromIndex:1]];
}
NSArray *sortedArray = [num sortedArrayUsingComparator:^(NSString *str1, NSString *str2){
return [#([str1 intValue]) compare:#([str2 intValue])];
}];
[array removeAllObjects];
for(int i=0;i<sortedArray.count;i++)
{
NSString *newString = [NSString stringWithFormat:#"P%#",sortedArray[i]];
[array addObject:newString];
}
It's work for me

Using NSPredicate to filter an object and a key(that needs to be split)

I have the following dictionary set up(Object, Key)
0, "10;0.75,0.75"
1, "0;2.25,2.25"
3, "1;3.5,2.0"
4, "1;4.5,3.0"
5, "2;6.0,5,0"
What I want to filter will be based on the object AND the key. The object is a NSNumber. The key is a string but i really don't want the entire string. I want to split the string separated by the semicolon and take the first index of the split which would yield the strings 10,0,1,1 or 2 depending on which object I was looking for.
As a specific example:
Are there any keys that are equal to #"1" with an object that is greater than 3.
In this case i should expect back YES since object 4 has a key that is equal to #"1", after i do the split.
I guess I was looking for a clever way to define a NSPredicate to do the split on the key separated by the semicolon and then filter(compare, etc) based on that. Let me know if you have any questions or need additional info.
A very naive implementation that I could think of
- (BOOL)hasKey:(NSString *)key withValueGreaterThan:(id)object{
NSDictionary *dictionary = #{#"10;0.75,0.75": #0,
#"0;2.25,2.25" : #1,
#"1;3.5,2.0" : #3,
#"1;4.5,3.0" : #4,
#"2;6.0,5,0" : #5};
NSPredicate *keyPredicate = [NSPredicate predicateWithFormat:#"SELF BEGINSWITH %#",key];
NSArray *filteredKeys = [[dictionary allKeys]filteredArrayUsingPredicate:keyPredicate];
for (NSString *k in filteredKeys) {
NSNumber *value = dictionary[k];
if (value>object) {
return YES;
}
}
return NO;
}
Use
BOOL hasValue = [self hasKey:#"1;" withValueGreaterThan:#3];
Sample Code:
NSDictionary* dict = #{ #"10;0.75,0.75":#0,
#"0;2.25,2.25":#1,
#"1;3.5,2.0":#3,
#"1;4.5,3.0":#4,
#"2;6.0,5,0":#5};
__block NSString* foundKey = nil;
[dict enumerateKeysAndObjectsUsingBlock:^(NSString* key, NSNumber* obj, BOOL *stop) {
//here goes condition
//get substr
NSArray* arr = [key componentsSeparatedByString:#";"];
int num = [[arr objectAtIndex:0]integerValue];
if ((num == 1)&&([obj integerValue]>3)) {
foundKey = key;
stop = YES;
}
}];
if (foundKey) {
NSLog(#"%#:%#",foundKey,[dict objectForKey:foundKey]);
}
Just use the following method:
-(BOOL)filterFromDictionary:(NSDictionary*)dict keyEqual:(NSString*)key greaterthanObj:(NSString*)obj
{
NSArray *allKeys = [dict allKeys];
for (NSString *eachkey in allKeys) {
NSString *trimmedKey = [self trimKeyuntill:#";" fromString:eachkey];
NSString *trimmedValue = [dict objectForKey:eachkey];
if ([trimmedKey isEqualToString:key] && [trimmedValue intValue] > [obj intValue]) {
return YES;
}
}
return NO;
}
call the above method with your dictionary like:
NSDictionary *dict = [NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:#"1",#"1",#"3",#"4",#"5", nil] forKeys:[NSArray arrayWithObjects:#"10;0.75,0.75",#"0;2.25,2.25",#"1;3.5,2.0",#"1;4.5,3.0",#"2;6.0,5,0", nil]];
[self filterFromDictionary:dict keyEqual:#"1" greaterthanObj:#"3"]
I assumed all your objects are nsstrings. otherwise change the intValue

Resources