iOS: array that contains other two array - objective-c

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.

Related

Add missing years and corresponding values into arrays

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.

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**);
}

Non-repeating arc4random_uniform

I've been trying to get non-repeating arc4random_uniform to work for ages now for my iPhone app. Been over all the questions and answers relating to this on stackoverflow with no luck and now I'm hoping someone can help me. What I want to do is is choose 13 different random numbers between 1 and 104. I have gotten it to work to the point of it choosing 13 different numbers, but sometimes two of them are the same.
int rand = arc4random_uniform(104);
This is what I'm doing, and then I'm using the rand to choose from an array. If it's easier to shuffle the array and then pick 13 from the top, then I'll try that, but I would need help on how to, since that seems harder.
Thankful for any advice.
There's no guarantee whatsoever that ar4random_uniform() won't repeat. Think about it for a second -- you're asking it to produce a number between 0 and 103. If you do that one hundred and five times, it has no choice but to repeat one of its earlier selections. How could the function know how many times you're going to request a number?
You will either have to check the list of numbers that you've already gotten and request a new one if it's a repeat, or shuffle the array. There should be any number of questions on SO for that. Here's one of the oldest: What's the Best Way to Shuffle an NSMutableArray?.
There's also quite a few questions about non-repeating random numbers: https://stackoverflow.com/search?q=%5Bobjc%5D+non-repeating+random+numbers
You can create an NSMutableSet and implement it like this:
NSMutableArray* numbers = [[NSMutableArray alloc] initWithCapacity: 13];
NSMutableSet* usedValues = [[NSMutableSet alloc] initWithCapacity: 13];
for (int i = 0; i < 13; i++) {
int randomNum = arc4random_uniform(104);
while ([usedValues containsObject: [NSNumber numberWithInt: randomNum]) {
randomNum = arc4random_uniform(104)
}
[[usedValues addObject: [NSNumber numberWithInt: randomNum];
[numbers addObject: [[NSNumber numberWithInt: randomNum];
}
Alternatively you can also create a mutable array of 105 integers each a unique one, and arc4random_uniform([arrayname count]) and then delete that same one from the array, then you'll get a random int each time without repeating (though the smaller the array gets the easier it is to predict what the next number will be, just simple probability)
The best algorithm that I have found for this exact question is described here:
Algorithm to select a single, random combination of values?
Instead of shuffling an array of 104 elements, you just need to loop through 13 times. Here is my implementation of the algorithm in Objective C:
// Implementation of the Floyd algorithm from Programming Pearls.
// Returns a NSSet of num_values from 0 to max_value - 1.
static NSSet* getUniqueRandomNumbers(int num_values, int max_value) {
assert(max_value >= num_values);
NSMutableSet* set = [NSMutableSet setWithCapacity:num_values];
for (int i = max_value - num_values; i < max_value; ++i) {
NSNumber* rand = [NSNumber numberWithInt:arc4random_uniform(i)];
if ([set containsObject:rand]) {
[set addObject:[NSNumber numberWithInt:i]];
} else {
[set addObject:rand];
}
}
return set;
}

NSMutableArray cannot remove duplicates

I have duplicates in my array and i want to get rid of them, so i run this loop, however it doesn't work. Any one know why?
The array currently has 3 items, 2 duplicates and 1 unique.
for (int x = 0; x <= [array count]; x++) {
if(x > 0){
if([[array objectAtIndex:x - 1] isEqualToString:[array objectAtIndex:x]]){
[array removeObjectAtIndex:x];
}
}
}
You can't iterate over an object and modify it at the same time. Once you remove an object, the indexes of all the objects change. You can try copying the array first and iterate that and make the modifications in the original array, but you still might have to change some of your logic depending on what you're trying to accomplish.
Your algorithm only ever compares items that are next to each other in the array (the items at positions x and x-1). If the duplicates are in any other positions, they won't be found.
The naïve way to fix this is to do a double loop. Compare each item in the array with every item after it. This will start taking an extremely long time as your array becomes bigger.
The correct way to do this is to let the framework handle the operation. Convert your array to a set (which does not have duplicates by definition) and then back to an array:
NSSet * s = [NSSet setWithArray:array];
NSArray * dedupedArray = [s allObjects];
If you need to preserve the order, you'll have to do this in a slightly roundabout way, although this is still faster than the double-loop:
NSMutableSet * itemsSeen = [NSMutableSet set];
NSMutableArray * dedupedArray = [NSMutableArray array];
for( id item in array ){
if( ![itemsSeen containsObject:item] ){
[itemsSeen addObject:item];
[dedupedArray addObject:item];
}
}
I would suggest simply using NSSet ( or NSMutableSet ). It will automatically ensure you have only one of every object.
BUT - notice it is one of every OBJECT. It can have 2 objects that are different but have the same inner value.
If you want to ensure that there are no duplicates in your array, it would be better to use an NSMutableSet rather than an NSMutableArray.
NSMutableSet maintains the invariant that every object in the set is unique.
For example:
NSMutableSet* set = [NSMutableSet set];
NSString* data = #"Data";
[set addObject:data];
[set addObject:data];
The second call to addObject: will do nothing as data is already in the set.

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.