Add missing years and corresponding values into arrays - objective-c

I've been messing around with the JBChartView library and it seems really good for charting. It's easy enough to use but i'm having some problems getting my data in a format that i need for a particular chart.
The user can enter a value and corresponding year. This is saved using core data. The data could look like as follows:
Year: 0 Value: 100
Year:2 Value 200
Year 3 Value 150
I would create 2 arrays, 1 for the year number and another for the value. in this case though, I would get 3 bars. What i'd like is a bar with value 0 for Year 1.
I think the best way to approach this would be to look through the Year array, check to see if the first value is 0, then check if every consecutive year value is +1. If not, add 1 to the previous year and insert a value of 0 into the values array at the same index position.
I would like to know if this is the best approach and if I could get some help doing the comparison.
Thanks

Ok I got to an answer to my own question and thought i'd post it as it may help someone in the future, especially when creating charts using this, or other libraries.
I first populate 2 mutable arrays
chartLegend = [NSMutableArray arrayWithObjects:#1,#3, nil];
chartData = [NSMutableArray arrayWithObjects:#"100",#"300", nil];
So i've got years 1 and 3, each with an associated value in the chartData array.
i now need to create a year 0 and year 2 so that my bar chart has a bar for every year from 0 to my maximum year, 3.
- (void)addItemsToArray {
for (int i=0; i<[chartLegend count]; i++)
{
//get the values from our array that are required for any calculations
int intPreviousValue = 0;
int intCurrentValue = [[chartLegend objectAtIndex:i]integerValue];
if (i>0)
{
intPreviousValue = [[chartLegend objectAtIndex:(i-1)]integerValue];
}
//Deal with the first item in the array which should be 0
if (i == 0)
{
if (intCurrentValue != 0)
{
[chartLegend insertObject:[NSNumber numberWithInt:0] atIndex:i];
[chartData insertObject:[NSNumber numberWithInt:0] atIndex:i];
}
}
//Now deal with all other array items
else if (intCurrentValue - intPreviousValue !=1)
{
int intNewValue = intPreviousValue +1;
[chartLegend insertObject:[NSNumber numberWithInt:intNewValue] atIndex:i];
[chartData insertObject:[NSNumber numberWithInt:0] atIndex:i];
}
}
//create a string with all of the values in the array
NSString *dates = [chartLegend componentsJoinedByString:#","];
NSString *values = [chartData componentsJoinedByString:#","];
//display the text in a couple of labels to check you get the intended result
self.yearsLabel.text = dates;
self.valuesLabel.text = values;
}
That seems to be working for me. It should be easy enough to populate your arrays using coreData information, just make sure it's sorted first.

Related

Random Generator slightly less random

NSPredicate *predicate = [NSPredicate predicateWithFormat:#"category == %#", selectedCategory];
NSArray *filteredArray = [self.Quotes filteredArrayUsingPredicate:predicate];
// Get total number in filtered array
int array_tot = (int)[filteredArray count];
// As a safeguard only get quote when the array has rows in it
if (array_tot > 0) {
// Get random index
int index = (arc4random() % array_tot);
// Get the quote string for the index
NSString *quote = [[filteredArray objectAtIndex:index] valueForKey:#"quote"];
// Display quote
self.quote_text.text = quote;
// Update row to indicate that it has been displayed
int quote_array_tot = (int)[self.Quotes count];
NSString *quote1 = [[filteredArray objectAtIndex:index] valueForKey:#"quote"];
for (int x=0; x < quote_array_tot; x++) {
NSString *quote2 = [[Quotes objectAtIndex:x] valueForKey:#"quote"];
if ([quote1 isEqualToString:quote2]) {
NSMutableDictionary *itemAtIndex = (NSMutableDictionary *)[Quotes objectAtIndex:x];
[itemAtIndex setValue:#"DONE" forKey:#"source"];
}
}
Above is the code I use in my app for generating a random quote from one of two categories stored in a plist (in arrays, where the first line is category, and second is quote). However, it seems to have a preference of repeating ones it's already shown. I'd prefer it have a preference (but not exclusively) show ones it hasn't shown before.
Your question is an algorithm question. What you want is a sequence of numbers that seems random but is more uniform.
What you are looking for is called a low-discrepancy sequence. A simple form of this is a "shuffle bag", often used in game development, as described here or here.
With a shuffle bag, you basically generate all the indices (e.g. 0 1 2 3 4 5), shuffle them (e.g. 2 3 5 1 0 4) and then display the elements in this order. At the end, you generate another sequence (e.g. 4 1 0 2 3 5). Note that it is possible that the same element appears twice in the sequence, although it is rare. E.g. in this case, the "4" is a duplicate, because the full sequence is 2 3 5 1 0 4 4 1 0 2 3 5.
arc4random() is a good PRNG on Apple platforms, so it doesn't give you a "low discrepancy sequence". But: you can use it as a primitive to generate "low discrepancy sequences", you can also use it as a primitive to create a shuffle bag implementation.

compaire NSArray items with every other item in the NSArray

I have an NSArray of NSStrings and would like to know how to compare each item in the array with every other item in the array to see if there is any strings different from the rest.
I have seen a c++ example
for (int i = 0; i < list.size(); i++) {
for (int j = i+1; j < list.size(); j++) {
// compare list.get(i) and list.get(j)
}
}
but was woundering if there is a better easier way in objective C? also the other thing I need to do is make sure the item doesn't compare itself while it loops through.
Any help or examples would be greatly appreciated.
UPDATE ** BOLD is the updated part of the question **
If I read your question correctly, you want the strings that only appear once in the list, correct?
NSCountedSet *counted = [NSCountedSet setWithArray:list];
for (NSString *string in counted) {
NSUInteger count = [counted countForObject:string];
if (count == 1) {
// process "string", it appears in the list just once
}
}
If you just want to know if there is more than one different value in the list then do this:
NSSet *set = [NSSet setWithArray:list];
if (set.count == 1) {
// There is only one distinct value in the list
} else {
// There is more than one distinct value in the list
}
I'd use an NSMutableDictionary. This is very similar to "merging two lists into unique values", the apple docs actually explain the complicated way somewhere. I forgot where I found it, but the easy way is here: Merge two arrays while preserving the original array order
So what you'd do is loop through everything, see if there's a key (set to the string), if not, add one via the setObject: forKey: method, then enumerate through the dictionary or just grab the allKeys value after.
Use two sets. If the string goes into the first set without conflict, add it to the second set. If the string encounters a conflict in the first set, remove it from the second set. When you've processed all the strings the second set contains the unique ones.

Getting Top 10 Highest Numbers From Array?

I am having a bit of a issue. I have an NSMutableDictionary with 10 NSMutableArrays in it. Each array has somewhere between 0-10 numbers which could each be any integer, e.g. 12 or 103.
What I need to do is get the top 10 highest numbers from across each of the arrays. The trouble is, I need to keep a reference of the array it came from in the dictionary (the key) and the index position of the number from the array it came form.
Easiest way, is to sort the array in Descending order, and then grab the first 10 indexes
Or if they are inside dictionaries, iterate the dictionary allValues, grab all the arrays, add all the elements inside a common array, and sort that
It seems as if the data structure you want to end up with is an array of objects, where each object is functionally similar to an "index path" except that it's composed of a string (key) and a value (offset).
Assuming that the actual search for highest numbers isn't in question, then I'd suggest creating one of these objects whenever you find a candidate number so that, once the top ten are found, the objects can be used as back-pointers to the numbers' source locations.
Sounds like some sort of homework :)
So you have this:
NSMutableDictionary* source = [#{
#"1" : #[ #10, #20, #100 … ],
#"2" : #[ #8, #42, #17 … ]
} mutableCopy];
So lets start by creating another arrangement:
NSMutableArray* numbers = [NSMutableArray new];
for (NSArray* array in source.allValues)
{
for (NSNumber* number in array)
{
[numbers addObject: #{ #"number" : number, #"parent" : array }];
}
}
This is what we get:
#[
#{ #"number" : #10, #"parent" : <array> },
#{ #"number" : #20, #"parent" : <array> },
…
]
Now we can sort and find the numbers you wanted.
[numbers sortUsingComparator: ^( id lhs, id rhs ){
return [((NSDictionary*) rhs)[#"number"] compare: ((NSDictionary*) lhs)[#"number"]];
}];
NSArray* topNumbers = [numbers subarrayWithRange: NSMakeRange( 0, 10 )];
Here we are. topNumbers contains the numbers you needed along the source array.
This is quite a naive way to do it. It can be optimized both in CPU time and memory usage by a fair amount. But hey, keep it simple is not a bad thing.
Not addressed: what if the tenth and eleventh numbers are equal? (adressed here: Pick Out Specific Number from Array?) range checks. not tested, not even compiled. ;)
Walk through the arrays creating an object/structure for each element, consisting of the numeric "key" value and the "path" (array indices) to the element. Sort the objects/structures so created. (This is referred to as a "tag sort".)
The other approach, if you only need the top N values (where N << total number of entries) is to create an array of N elements, consisting of the above key and path info. Scan through all the arrays and compare each array element to the smallest key of the N currently stored. If you find an element larger than the smallest stored, replace the smallest stored and sort the N elements to select a new smallest stored.
You have to short your array in descending order using 'C' logic. Here i'm going to give an example according to your condition....
// adding 20 elements in an array, suppose this is your original array (array1).
NSMutableArray *array1 = [[NSMutableArray alloc]init];
for(int i=0;i<20;i++)
{
NSString *str = [NSString stringWithFormat:#"%d",(i*4)];
[array1 addObject:str];
}
//make a copy of your original array
NSMutableArray *array2 = [[NSMutableArray alloc]initWithArray:array1];
// this is the array which will get your sorting list
NSMutableArray *array3 = [[NSMutableArray alloc]init];
//declare an integer for compare as a maximum number and it to 0 initially
int max = 0;
// this is the logic to sort an array
for(int i=0;i<20;i++)
{
for(int j=0;j<[array2 count];j++)
{
int f = [[array2 objectAtIndex:j] intValue];
if(max<f)
{
max = f;
}
}
NSString *str = [[NSNumber numberWithInt:max]stringValue];
//max has a maximum value then add it to array3 and remove from array2
//for a new shorting
[array3 addObject:str];
[array2 removeObject:str];
// set 0 to max again
max = 0;
}
//now after all procedure print the **array3**
// and you will get all the objects in descending order,
//you can take top **10** variables from **array3**
NSLog(#"your sorting array %#", **array3**);
}

count NSMutableArray size till or from a specific word?

I have got an array, I know how to count its elements, but I need to count elements until a specific word:
NSMutableArray *whatBondInFrame;
whatBondInFrame=[NSMutableArray arrayWithObjects:#"red",#"red",#"red",#"gray",#"red",#"ran",#"gray",#"gray",nil];
I know [ whatBondInFrame count] but, let's say I want to know how many elements I have till the first gray or from the word "ran".
How would I get that?
This isn't tested but it should work:
int loc = 0;
for (loc; loc < [array count]; loc++) {
NSString *str = [array objectAtIndex:loc];
if ([str isEqualToString:#"ran"])
break;
}
int length = array.count-loc;
this gives you the count from the first element named ran.
If you want to know how many elements there are before (till) the word 'ran' then replace the last line with
int length = loc
The NSArray method:
- (NSUInteger)indexOfObject:(id)anObject
Will return the index of the first occurrence on an object, so you can do:
NSUInteger firstRanIndex = [whatBondInFrame indexOfObject:#"ran"];
There is a companion method:
- (NSUInteger)indexOfObject:(id)anObject inRange:(NSRange)range
Which restricts the search to a given range of the array. There is no method to find the last occurrence, for that you must loop with the above methods.
In conjunction with the count method you can get the numbers you want.

iOS: array that contains other two array

In my project I must store a value for a period;
Example: I have three buttons where I can choose a value: I have a button for "10" another for "100" and another for "1000".
When I press a button I open a view where I can choose a period for these value: then for example I press "100", and I select period by 15/05/2011 at 20/05/2011 and press ok.
The result is that at the month "May" in day 15 there is value 100, in day 16 there is value 100.....and in day 20 there is value 100.
Can I organize this method with an array of month where in an index there is another array of days and inside every days there is the value 100? But I don't know how to do this...Can you help me?
From what I gather in your question... you basically want an array of months, and within each month you have an array of days, and for each day you have an array of values? or just the value?
Either way, what you can do is just nesting arrays. So you have one NSArray, and all the objects within that NSArray are also NSArrays and so on and so forth until you get the structure you want.
If you could provide a more clear explanation of what exactly you wish to achieve then I might be able to elaborate on my answer, but I think this might get you onto the right track?
NSMutableArray *months = [[NSMutableArray alloc] init];
for (int i = 0; i &lt 12; i++) {
NSMutableArray *days = [[NSMutableArray alloc] init];
for (int j = 0; j &lt 30; j++) {
NSMutableArray *values = [NSMutableArray alloc] init];
[days addObject:values];
[values release];
}
[months addObject:days];
[days release];
}
I don't have my mac around so forgive me for any errors, but I think you want something like this?
So in the "months" array, there are 12 "days" arrays, and for each "days" array, there are 30 "values" arrays where you can add your values.
NOTE: You will have to put in your logic to check for the actual amount of days there are in each month, as this code will just assume every month has 30 days.