I have a NSDictionary that contains objects and keys. The Keys hold a Name and number. I would like to insert those objects into a NSMutableArray by using insertObject: atIndex: . Object being the name and the number is the index I would like to place the object in. I now know that NSMutableArrays are able to insert objects at index:6 if there is no 1-5 so how do I make this possible? Any suggestions are very appreciated!
Example Dictionary [dict objectForKey:#"array"]:
preferences as whole (
{
Name = PowerDown;
btnIndex = 3;
},
{
Name = ClearCache;
btnIndex = 5;
},
{
Name = KillBGApps;
btnIndex = 6;
},
{
Name = InfoPanel;
btnIndex = 2;
},
{
Name = Lock;
btnIndex = 4;
},
{
Name = Reboot;
btnIndex = 0;
},
{
Name = Respring;
btnIndex = 1;
}
)
What I have so far but crashes when adding objects out of bounds of the array
-(void)loadArray{
self.buttons = [NSMutableArray array];
NSMutableArray *tempArray = [[NSMutableArray alloc] init];
tempArray = [buttonsPrefs objectForKey:#"buttonsToOrder"];
for(NSDictionary * dict in tempArray)
{
if (dict) {
NSString *btnName = [dict objectForKey:#"Name"];
NSString *btnIndex = [dict objectForKey:#"btnIndex"];
NSUInteger index = [btnIndex integerValue];
NSLog(#"Name = %#",btnName);
NSLog(#"at index %i",index);
[self.buttons insertObject: btnName atIndex: index];
}
}
}
EDIT: These values "indexes" for the names with change when a user moves the cell
- (void) tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath
*)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath {
NSUInteger fromIndex = [fromIndexPath row];
NSUInteger toIndex = [toIndexPath row];
if (fromIndex == toIndex)
return;
NSMutableDictionary *selectedButton = [[[_buttons objectAtIndex:fromIndex] retain]
autorelease];
[_buttons removeObjectAtIndex:fromIndex];
[_buttons insertObject:selectedButton atIndex:toIndex];
//[buttonsPrefs setObject:_buttons forKey:#"buttonsToOrder"];
//[buttonsPrefs writeToFile:[self getFilePath] atomically: YES];
}
Try to fill your target array with some dummy data according to yourDict count like this:
for (int i=0, i<[yourDict count], ++i){
[yourArray addObject:#"dummyData"];
}
And when you will need to insertObject do this:
for(NSDictionary * dict in tempArray)
{
if (dict) {
NSString *btnName = [dict objectForKey:#"Name"];
NSString *btnIndex = [dict objectForKey:#"btnIndex"];
NSUInteger index = [btnIndex integerValue];
[yourArray insertObject:btnName atIndex:index];
[yourArray removeObjectAtIndex:index+1];
}
}
NSMutableArray insertObject: atIndex:
as per apple docs `
"Note that NSArray objects are not like C arrays. That is, even though
you specify a size when you create an array, the specified size is
regarded as a “hint”; the actual size of the array is still 0. This
means that you cannot insert an object at an index greater than the
current count of an array."
Can only fill within valid array value set.Two things you can do.
Sort and fill the array
Fill the array with some default object like a string(cannot be nil) and then replace it.This option is valid if you are filling all the values in array because when used later you have to check weather the value is right there or the default value is in that position
Related
I have a UITableView that gets populated via an array (tableArray), who gets populated from core data.
each UITableViewCell gets assigned a number at creation time and the numbers are stored in an array. (numberArray)
when the user reorders the rows, the numbers get moved around in the array (in conjunction with the tableView of course)
So two Mutable arrays are used here.
The numberArray holds the numbers (or the order) of the TableViewCells.
I need to sort the array that holds the UITableViewCell's text (tableArray)
to reflect the same order that the numberArray holds.
Also, this is important: as i said before, each cell gets assigned a number, this number is stored in the numberArray,
I need both of the arrays to be sorted to hold the same values in the same place.
So for example:
tableArray hold some objects:
1) hi
2) whats Up
3) this
4) is cool!
so as you can see each object here was assigned a number 1-4.
and each of these numbers is added to the numberArray.
The user can move the cells around so obviously the order of the numbers will change.
So when the view loads up, i need to get the exact order of the numberArray whether it is
1,2,3,4 or 2,4,3,1
and i need to sort the tableArray to reflect the same order as the numberArray
so when the view loads up, if the numberArray's order is 2,3,4,1 i want the tableArray's order to be set to
2"whats up", 3"this", 4"is cool!", 1"hi".
I believe i can do this via NSPredicate.
Any help is greatly appreciated!
EDIT
cellForRow:
-(UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString * identifier = #"identifier";
self.myCell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (self.myCell == nil) {
self.myCell = [[CustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
}
HandgunAmmo *handgunAmmo = [self.tableArray objectAtIndex:indexPath.row];
self.myCell.brandLabel.text = handgunAmmo.brand;
self.myCell.caliberLabel.text = handgunAmmo.caliber;
self.myCell.numberOfRoundsLabel.text = handgunAmmo.numberOfRounds;
return self.myCell;
}
And in my viewWIllAppear method:
-(void)viewWillAppear:(BOOL)animated{
if (self.context == nil)
{
self.context = [(RootAppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
}
NSFetchRequest *request = [[NSFetchRequest alloc]init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"HandgunAmmo" inManagedObjectContext:self.context];
[request setEntity:entity];
NSError *error;
NSMutableArray *array = [[self.context executeFetchRequest:request error:&error] mutableCopy];
[self setTableArray:array];
[self.ammoTable reloadData];
[super viewWillAppear:YES];
}
So, the reason why the array doesnt stay persistent when being changed is because im loading the data from core data, and i call [self setTableArray:array]; which reloads all of the data from core data into the array, then it populates the tableview with the array. So i need to be able to sort the array before i set it equal to self.tableArray.
Thank you for the help!
Why don't you leave the tableArray unchanged, and use the numberArray as an index into the other array.
You would initialize the numberArray to 0, 1, 2, ..., n-1 with
numberArray = [NSMutableArray array];
for (NSUInteger i = 0; i < [tableArray count]; i++) {
[numberArray addObject:[NSNumber numberWithUnsignedInteger:i]];
}
When you need an item, e.g. in cellForRowAtIndexPath, you access it via the index:
NSUInteger i = [[numberArray objectAtIndex:row] unsignedIntegerValue];
NSString *item = [tableArray objectAtIndex:i];
Now you need to reorder the numberArray only, and the changes will automatically be reflected in the table view.
Update: A good solution to handle the reordering of Core Data objects in a table view can be found here: UITableView Core Data reordering
I cant see a way to solve it with a predicate
NSArray *stringArray = #[#"hi", #"what's up?", #"this", #"is cool"];
NSArray *numberArray = #[#2, #4, #3, #1];
NSMutableArray *combinedArray = [NSMutableArray array];
//connect string with the numbers of there new position
[numberArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSString *string =stringArray[[obj integerValue]-1];
[combinedArray addObject:#[string, obj]];
}];
NSMutableArray *orderedArray = [NSMutableArray array];
[combinedArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
[orderedArray addObject:obj[0]];
}];
NSLog(#"%#", orderedArray);
result
(
"what's up?",
"is cool",
this,
hi
)
NSMutableArray *unsortedArray = [NSMutableArray arrayWithObjects:#"1) hi",#"2) whats Up",#"3) this",#"4) is cool!",nil];
NSArray *guideArray = [NSArray arrayWithObjects:#"2",#"4",#"3",#"1", nil];
for(int i=0; i< [guideArray count];i++)
{
for(int j=0; j< [unsortedArray count];j++)
{
if([[[unsortedArray objectAtIndex:j] substringToIndex:[[guideArray objectAtIndex:i] length]] isEqualToString:[guideArray objectAtIndex:i]])
//if([[unsortedArray objectAtIndex:j] containsObject:[guideArray objectAtIndex:i]])
{
[unsortedArray exchangeObjectAtIndex:j withObjectAtIndex:i];
break;
}
}
}
NSLog(#"%#",unsortedArray);
OR
guideArray = #[#"2",#"4",#"3",#"1"];
unsortedArray = [#[#[#"1) hi"],
#[#"2) wats up "],
#[#"3) this,"],
#[#"4) cool"]] mutableCopy];
[unsortedArray sortUsingComparator:^(id o1, id o2) {
NSString *s1 = [o1 objectAtIndex:0];
s1 = [s1 substringToIndex:[s1 rangeOfString:#")"].location];
NSString *s2 = [o2 objectAtIndex:0];
s2 = [s2 substringToIndex:[s2 rangeOfString:#")"].location];
NSInteger idx1 = [guideArray indexOfObject:s1];
NSInteger idx2 = [guideArray indexOfObject:s2];
return idx1 - idx2;
}];
NSLog(#"%#",unsortedArray);
Try this hope this help partially.
I am working on SQLite and I have written a query which returns me two arrays ItemsArray and CustomersIDArray as:
ItemsArray
Element at Index 0 = Off White,
Element at Index 1 = Fan,
Element at Index 2 = Off White,
Element at Index 3 = Delux,
Element at Index 4 = Fan
CustomerIDArray
Element at Index 0 = 1,
Element at Index 1 = 2,
Element at Index 2 = 2,
Element at Index 3 = 3,
Element at Index 4 = 4
I want result like that Off White = 2 (count) , Fan = 2 (count) and Delux = 1;
and the Resultant Array,
Result Array
Element at Index 0 = Off White,
Element at Index 1 = Fan,
Element at Index 2 = Delux
Actually I want the count of repetition in first array but the value must not same for CustomerArray.
Please help me through logic or code.
-(NSMutableArray *)getCountAndRemoveMultiples:(NSMutableArray *)array{
NSMutableArray *newArray = [[NSMutableArray alloc]initWithArray:(NSArray *)array];
NSMutableArray *countArray = [NSMutableArray new];
int countInt = 1;
for (int i = 0; i < newArray.count; ++i) {
NSString *string = [newArray objectAtIndex:i];
for (int j = i+1; j < newArray.count; ++j) {
if ([string isEqualToString:[newArray objectAtIndex:j]]) {
[newArray removeObjectAtIndex:j];
countInt++;
}
}
[countArray addObject:[NSNumber numberWithInt:countInt]];
countInt = 1;
}
NSMutableArray *finalArray = [[NSMutableArray alloc] initWithObjects:newArray, countArray, nil];
NSLog(#"%#", finalArray);
return finalArray;
}
- (IBAction)getArrayInfo:(id)sender {
NSMutableArray *myArray = [[NSMutableArray alloc] initWithObjects:#"Off White", #"Fan", #"Off White", #"Deluxe", #"Fan", nil];
NSMutableArray *godArray = [self getCountAndRemoveMultiples:myArray];
NSLog(#"Array from this end = %#", godArray);
}
I just set up -getArrayInfo to test it out. Works fine. As you can see, the array you want to display will be at index:0, and the countArray at index:1.
Use NSCountedSet like below
NSMutableArray *ary_res = [[NSMutableArray alloc] init];
NSMutableArray *array = [[NSMutableArray alloc] initWithObjects:#"11",#"13",#"34",#"9",#"13",#"34",#"9",#"2",nil];
NSCountedSet *set = [[NSCountedSet alloc] initWithArray:array];
for(id name in set)
{
if([set countForObject:name]==2)
[ary_res addObject:name];
}
//
NSLog(#"%#",ary_res);
try this:
NSArray *copy = [ItemsArray copy];
NSInteger index = [copy count] - 1;
for (id object in [copy reverseObjectEnumerator]) {
if ([ItemsArray indexOfObject:object inRange:NSMakeRange(0, index)] != NSNotFound) {
[ItemsArray removeObjectAtIndex:index];
}
index--;
}
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 have used a number of grouped tables tied to core data managed objects, where the sectionNameKeyPath value is used to identify the attribute in the data that should be used to denote sections for the table.
But how do I indicate the "sectionNameKeyPath equivalent" when I have a table that is being use to present an NSMutableArray full of objects that look like this:
#interface SimGrade : NSObject {
NSNumber * scoreValue;
NSString * commentInfo;
NSString * catName;
}
I would like to have sections defined according to the "catName" member of the class.
Consider, for example that my mutablearray has 5 entries where the 5 "catName" values are "Blue", "Blue", "Blue", "Red", and "Red". So I'd want the number of sections in the table for that example to be 2.
So, what I would 'like to do' could be represented by the following pseudo-code:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return (The number of unique catNames);
}
Note: My interest in doing this is not so much for displaying separate sections in the table, but rather so that I can more easily calculate the sums of scoreValues for each category.
<<<<< UPDATE >>>>>>>>>
Joshua's help, as documented in his response has been right on. Here are the two new handlers for number of sections and number of rows per section...
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
NSMutableSet *counter = [[NSMutableSet alloc] init];
[tableOfSimGrades enumerateObjectsUsingBlock:^(id object, NSUInteger idx, BOOL *stop) {
[counter addObject:[object catName]];
}];
NSInteger cnt = [counter count];
[counter release];
NSLog(#">>>>> number of sections is -> %d", cnt);
return cnt;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
NSMutableDictionary *counter = [[NSMutableDictionary alloc] init];
NSMutableArray *cats = [[NSMutableArray alloc] init];
__block NSNumber *countOfElements;
[tableOfSimGrades enumerateObjectsUsingBlock:^(id object, NSUInteger idx, BOOL *stop) {
// check the dictionary for they key, if it's not there we get nil
countOfElements = [counter objectForKey:[object catName]];
if (countOfElements) {
// NSNumbers can't do math, so we use ints.
int curcount = [countOfElements intValue];
curcount++;
[counter setObject:[NSNumber numberWithInt:curcount] forKey:[object catName]];
NSLog(#">>>> adding object %d to dict for cat: %#", curcount, [object catName]);
} else {
[counter setObject:[NSNumber numberWithInt:1] forKey:[object catName]];
[cats addObject:[object catName]];
NSLog(#">>>>> adding initial object to dict for cat: %#", [object catName]);
}
}];
countOfElements = [counter objectForKey:[cats objectAtIndex: section]];
int catcount = [countOfElements intValue];
[counter release];
[cats release];
return catcount;
}
My current issue with this routine now lies in the following function... It is ignorant of any sections in the nsmutableArray and so for each section, it starts at index 0 of the array instead of at the 0th element of the appropriate section.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
}
// Configure the cell...
SimGrade *tmpGrade = [[SimGrade alloc] init];
tmpGrade = [tableOfSimGrades objectAtIndex: indexPath.row];
cell.detailTextLabel.text = [NSString stringWithFormat:#"Category: %#", tmpGrade.catName];
// [tmpGrade release];
return cell;
}
How do I transform the "indexpath" sent to this routine into the appropriate section of the mutableArray?
Thanks,
Phil
You could do something like this:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
NSMutableSet *counter = [[NSMutableSet alloc] init];
[arrayOfSims enumerateObjectsUsingBlock:^(id object, NSUInteger idx, BOOL *stop) {
[counter addObject:object.catName];
}];
NSInteger cnt = [counter count];
[counter release];
return cnt;
}
you'd probably want to memoize that, for performance reasons (but only after profiling it).
--- EDIT ---
You can use an NSMutableDictionary, too, to get counts of individual categories.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
NSMutableDictionary *counter = [[NSMutableDictionary alloc] init];
__block NSNumber *countOfElements;
[arrayOfSims enumerateObjectsUsingBlock:^(id object, NSUInteger idx, BOOL *stop) {
// check the dictionary for they key, if it's not there we get nil
countOfElements = [counter objectForKey:object.catName];
if (countOfElements) {
// NSNumbers can't do math, so we use ints.
int curcount = [countOfElements intValue];
curcount++;
[counter setObject:[NSNumber numberWithInt:curcount] forKey:object.catName];
} else {
[counter setObject:[NSNumber numberWithInt:1] forKey:object.catName];
}
}];
NSInteger cnt = [counter count];
// we can also get information about each category name, if we choose
[counter release];
return cnt;
}
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