Add array to second column of another array - ios

I'm new at Objective C. I have a list of questions, and each question has multiple answers, so I need to have an array which contains another array with a question number, then an array of answers.
I have an NSMutableArray which I'm instantiating it with this line:
_randomQuestionNumberArray = [[NSMutableArray alloc] initWithCapacity:2];
I fill this array with numbers:
for (int i = 0; i < numberOfQuestions; i++) {
NSNumber* xWrapped = [NSNumber numberWithInt:i];
[_randomQuestionNumberArray addObject:xWrapped];
}
Then I have another NSMutableArray which is just a regular array of numbers. I want to add this array to the second column of _randomQuestionNumberArray at a specific row. I'm using this code for this but it doesn't seem to work properly.
[_randomQuestionNumberArray insertObject:_tempAnswers atIndex:position];
Can anyone offer solution to this? Thank you!

Don't use an array of arrays. It will work initially, but it isn't flexible or clear (so hard to maintain).
Instead, use an array of dictionaries, where each dictionary has a number of keys:
_randomQuestionNumberArray = [NSMutableArray array];
for (int i = 0; i < numberOfQuestions; i++) {
[_randomQuestionNumberArray addObject:[#{ #"questionNumber" : #(i) } mutableCopy]];
}
then, when you have your answers:
NSMutableDictionary *questionDict = [_randomQuestionNumberArray objectAtIndex:...];
[questionDict setObject:_tempAnswers forKey:#"answers"];
and now it's obvious what each piece of information is for.
Note: the index of each item in the array could work as the question number if you wanted it to...

Try using this:
- (void)replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject;
in place of anObject put your array.

Related

assigning a value to an object's iVar inside an array [duplicate]

This question already has answers here:
Property '' not found on object of type 'id'
(2 answers)
Closed 6 years ago.
NSMutableArray *dataArray = [NSMutableArray array];
for (int i = 0; i<5; i++){
[dataArray addObject:[UITextView new]];
dataArray[i].text = "here";
^Property 'text' not found on object of type 'id'
}
I check the class, methods and iVars... everything is there, but I can't use them.
I want a UIScrollView with a user defined number of data fields (like 'Contants' app). So I load them into an array and put them onto the scroll view.
However, I can't call the methods. I want to use some kind of strut (array, dict, etc...)
I tried this:
textView1 = dataArray[i];
textView1.text = #"######### Here I am ##########";
But that doesn't seem to store in the object inside the array. I thought the array stored a pointer to the object and that textView1 would be a pointer to the object so it should store the value of '.text' to the same object.
What you tried seems a bit unclear to me, but this should work:
NSMutableArray *dataArray = [NSMutableArray array];
for (int i = 0; i<5; i++){
UITextView *t = [UITextView new];
[dataArray addObject:t];
t.text = #"here";
}

Strange dictionary sort ios objective c

I want to do kind of a weird dictionary sort. I have non-unique values and keys and get something like this
NSArray *counts = [#"1",#"2",#"2",#"3",#"6",#"10"];
NSArray *names =[#"Jerry",#"Marge",#"Jerry",#"Marge",#"Jen",#"Mark"];
The output that I want is an descending ordered list by counts with unique names. I don't want lower values of the same person in my outputted arrays. The output should be.
sortedNames=[#"Mark",#"Jen",#"Marge",#"Jerry"]
sortedCounts=[#"10",#"6",#"3",#"2"];
I would really appreciate some help on this.
NSMutableArray *userNameArray = [[NSMutableArray alloc] init];
NSMutableArray *countArray = [[NSMutableArray alloc] init];
for (NSDictionary *dict in bigDick) {
NSString *nameString =[dict objectForKey:#"Name"];
NSString *countString =[dict objectForKey:#"Count"];
NSInteger countInt = [countString integerValue];
NSNumber *countNumber =[NSNumber numberWithInt:countInt];
[userNameArray addObject:nameString];
[countArray addObject:countNumber];
}
NSArray *namesAscending =[[userNameArray reverseObjectEnumerator]allObjects];
NSArray *countsAscending=[[countArray reverseObjectEnumerator]allObjects];
// Put the two arrays into a dictionary as keys and values
NSDictionary *dictionary = [NSDictionary dictionaryWithObjects:countsAscending forKeys:namesAscending];
// Sort the first array
NSArray *sortedCountArray = [[dictionary allValues] sortedArrayUsingSelector:#selector(compare:)];
// Sort the second array based on the sorted first array
// NSArray *sortedNameArray= [dictionary objectsForKeys:sortedCountArray notFoundMarker:[NSNull null]];
NSMutableArray *nameArray =[[NSMutableArray alloc] init];
for (int i=1; i<sortedCountArray.count; i++) {
NSString *name = [dictionary allKeysForObject:sortedCountArray[i]];
if (sortedCountArray[i]!=sortedCountArray[i-1]) {
[nameArray addObject:name];
}
}
an old method is to manual sort the array with numbers, by searching on every iteraton for the biggest value, and when you find the max value take the name from the other vector at index of the max number and move it in new vector...
max = counts[0];
counter = 0;
for (int i=0;i<counts.count;i++)
{
temp = counts[i];
if (max<temp)
max = temp;
counter = i;
}
[new_names addObject: [names objectAtIndex:counter]];
[new_numbers addObject: max];
[numbers removeObjectAtIndex: counter];
[names removeObjectAtIndex:counter];
Try something like this. It should work if you do it this way.
Important! do not remove elements in for from array that you count for the for length.
Your problem is in your algorithm design, if you step through it a line at a time in the debugger you should see what it does and where it goes wrong.
We're not here to write you code, but let's see if we can go through one step of an algorithm to help you one your way:
Useful fact: If you lookup a key in a dictionary and that key does not exist the return value will be nil.
From this: you can use a dictionary to keep track of the names you have seen paired with the highest score so far. You obtain a name,score pair, lookup the name in the dictionary - if you get nil its a new name with a new high score. If it's not nil its the currently known high score, so you can compare and update.
That's a rough algorithm, let's try it. Before we start rather than using literal strings for keys everywhere let's define some constants. This has the advantage that we won't mistype the strings, the compiler will spot if we mistype the constant names. These can be defined at the file level or within a method:
const NSString *kName = #"Name";
const NSString *kCount = #"Count";
Now to the code, in a method somewhere, we'll need a dictionary:
NSMutableDictionary *highScores = [NSMutableDictionary new]; // a single dictionary rather than your two arrays
Now start your loop as before:
for (NSDictionary *dict in bigDict) // same loop as your code
{
and extract the two values as before:
NSString *nameString = dict[kName]; // same as your code, but using modern syntax
NSInteger countInt = [dict[kCount] integerValue]; // condense two lines of your code into one
Now we can lookup the name in our dictionary:
NSNumber *currentScore = highScores[nameString]; // get current high score for user, if any
If the name exists as a key this will return the current associated value - the score in this case, if there is no matching key this will return nil. We can test for this in a single if:
if (currentScore == nil // not seen user before, no high score
|| currentScore.integerValue < countInt) // seen user, countInt is greater
{
The above condition will evaluate to true if we either need to add the name or update its score. Adding & updating a key/value pair is the same operation, so we just need the line:
highScores[nameString] = #(countInt); // add or update score for user
and a couple of braces to terminate the if and for:
}
}
Let's see what we have:
NSLog(#"Output: %#", highScores);
This outputs:
Output: {
Jen = 6;
Jerry = 2;
Marge = 3;
Mark = 10;
}
Which is a step in the right direction. (Note: the dictionary is not sorted, NSLog just displays the keys in sorted order.)
Make sure you understand why that works, copy the code and test it. Then try to design the next phase of the algorithm.
If you get stuck you can ask a new question showing the algorithm and code you've developed and someone will probably help. If you do this you should include a link to this question so people can see the history (and know you're not trying to get an app written for you through multiple questions!)
HTH
Try this.
sortedArray = [yourArray sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)];
After sort your array then remove duplicates using following.
NSOrderedSet *orderedSet = [NSOrderedSet orderedSetWithArray: sortedArray];
NSArray *arrayWithoutDuplicates = [orderedSet array];

How do i get unique contents from my NSMutableArray?

I have a UITableView and am displaying contents from my NSMutableArray. Following is array format
(
{
Name = "ANS";
VersionNo = 6;
},
{
Name = "O-Hydro";
Version = 6;
},
{
Name = "ANS";
Version = 6;
},
{
Name = "ANTIChorosAnticholinergic";
Version = 6;
}
)
From this I need to display only unique "Name" (like in this I can see 2 "ANS" I need only one).
How can I do this in iOS?
I tried following but its not working
uniqueArray= [[NSMutableSet setWithArray: groupDetails] allObjects];
but in this way I can do only for NSArray not NSMutableArray.
Pls help me
You can use following line of code to convert your NSArray to NSMutableArray,
NSArray *uniqueArray= [[NSMutableSet setWithArray:groupDetails] allObjects];
NSMutableArray *myMutableArray = [[NSMutableArray alloc] initWithArray:uniqueArray];
You could simply add mutableCopy.
But wait, before you do it. Arrays and sets have two differences:
Arrays can contain duplicates, sets cannot.
Arrays are ordered, sets are not.
So doing what you are doing, you lose the duplicates (intentionally), but the order, too (probably not intentionally).
I do not know, whether this is important for you, but for other readers it might be. So it is the better approach to do that with NSOrderedSet instead of NSSet:
NSOrderedSet *uniqueList = [NSOrderedSet orderedSetWithArray:array];
In many cases an ordered set is exactly what you want. (Probably it has been from the very beginning and the usage of NSArray was wrong. But sometimes you get an array.) If you really want an array at the end of the day, you can reconvert it:
array = [uniqueList.array mutableCopy];
If you just want an array of unique name values, you can use #distinctUnionOfObjects with valueForKeyPath -
NSArray *uniqueArray=[groupDetails valueForKeyPath:#"#distinctUnionOfObjects.name"];
But if you want the array to contain the dictionaries that correspond to the unique names then you need to do a little more work -
NSMutableArray *uniqueArray=[NSMutableArray new];
NSMutableSet *nameSet=[NSMutableSet new];
for (NSDictionary *dict in groupDetails) {
NSString *name=dict[#"name"];
if (![nameSet containsObject:name]) {
[uniqueArray addObject:dict];
[nameSet addObject:name];
}
}

NSArray with objects that "might" be nil

I have 3 objects that might be or not initialized in a random order.
so, if objects "objectOne, "objectTwo", "objectThree" are initialized in this order with
myArray = [NSArray arrayWithObjects:objectOne,objectTwo,objectThree nil];
all objects get inside the array without problem but in my case objectOne, objectTwo might be nil and objectThree might not be nil, and in this case I would like myArray to return(count) 1.
if objectOne is nil but objectTwo and objectThree are not nil I want my array to return(count) 2.
In these 2 last cases my array always return nil. What would be the best approach to this?
There are no magic method can solve the problem for you, you need to build the array from NSMutableArray
NSMutableArray *array = [NSMutableArray array];
if (objectOne) [array addObject:objectOne];
if (objectTwo) [array addObject:objectTwo];
if (objectThree) [array addObject:objectThree];
arrays can't contain nil. There is a special object, NSNull ([NSNull null]), that serves as a placeholder for nil. You can put NSNull in an array, but I don't think that solves your problem either.
How about this:
Create an empty mutable array.
In 3 separate statements:
If objectOne is not nil, add it to the array
if objectTwo is not nil, add it to the array
If objectThree is not nil, add it to the array.
If you need your objects to be in random order, scramble the array afterwords:
for (int index = 0; index < array.count; index++)
{
int randomIndex = arc4random_uniform()
[array exchangeObjectAtIndex: index withObjectAtIndex: randomIndex];
}
This is known as a Fisher–Yates shuffle. (or a minor variation on Fisher-Yates, anyway.)
If you're doing this rarely and you aren't trying to make things neat, you can, of course, use a mutable array and either add or don't add the items one at a time in code, depending on whether they are nil.
If you're doing this frequently and you want a syntax that looks similar to the array literal notation, you can take advantage of the C preprocessor and C arrays to create a smarter NSArray class constructor that handles nil:
#define NSArrayWithCArray(array) \
[NSArray arrayWithCArray:cArray count:sizeof(cArray) / sizeof(cArray[0])];
id cArray[] = {
object1,
object2,
object3,
...
};
NSArray *array = NSArrayWithCArray(cArray);
and then define a method on NSObject that walks through the C array programmatically, dropping any nil values.
+ (NSArray *)arrayWithCArray:(__strong id[])cArray count:(NSUInteger)count {
NSMutableArray *array = [NSMutableArray arrayWithCapacity:count];
for (__strong id *item = cArray; item < cArray + count; item++) {
if (*item != nil) {
[array addObject:*item];
}
}
return array;
}
Note: The code above is untested, but at least close enough to give you an idea of how to do it. :-)

adding array in NSDictionary and ordering it [duplicate]

This question already has answers here:
how to change order of NSMutable array in same way another mutable arrays get changed
(5 answers)
Closed 9 years ago.
i have three array like below
names birthdate remanning
"Abhi Shah", "01/14", 300
"Akash Parikh", "12/09/1989", 264
"Anand Kapadiya", "12/01", 256
"Annabella Faith Perez", "03/02", 347
"Aysu Can", "04/14/1992", 25
"Chirag Pandya" "10/07/1987" 201
plz it will be great help if you give me code for how to add this three array in NSDictionary and then after ordering(ascending) whole dictionary in accordance to "remaning" array
Note in Dic everything should get changed. not only remaning array. names and birthdate should get changed in same way remaning days are getting changed
thank you so much in advance
I would advise you to change the design of your project and create a model for same as having properties :
#interface YourModel : NSObject
#property (strong) NSString *name;
#property (strong) NDDate *birthDate;
#property NSInteger remaining;
#end
And then create an NSMutableArray in your class, and go on to add them.
This will make your work easier, as searching, sorting, filtering , than handling 3 parallel arrays.
You have to take each record (names, birthdate, remanning ) in the dictionary or any structure. And array of that dictionary should be created. To sort the array as per your requirement any sorting mechanism can be used.
-(void)sort
{
//This is the array of dictionaries, where each dictionary holds a record
NSMutableArray * array;
//allocate the memory to the mutable array and add the records to the arrat
// I have used simple bubble sort you can use any other algorithm that suites you
//bubble sort
//
for(int i = 0; i < [array count]; i++)
{
for(int j = i+1; j < [array count]; j++)
{
NSDictionary *recordOne = [array objectAtIndex:i];
NSDictionary *recordTwo = [array objectAtIndex:j];
if([[recordOne valueForKey:#"remaining"] integerValue] > [[recordTwo valueForKey:#"remaining"] integerValue])
{
[array xchangeObjectAtIndex:i withObjectAtIndex:j];
}
}
}
//Here you get the sorted array
}
Hope this helps.
If you use the design proposed by Anoop, the sorting code using blocks would be something similar to this:
NSArray *sortedArray = [yourArray sortedArrayUsingComparator:^NSComparisonResult(id a, id b) {
NSInteger first = [(YourModel*)a remaining];
NSInteger second = [(YourModel*)b remaining];
return [first compare:second];
}];

Resources