Replace all keys in an array of dictionary in cocoa - cocoa

I have a mutable array that consist of array of dictionaries as:
NSArray *myArray
({
    {
        "COL_1" = Jhon;
        "COL_2" = 01/27/13;
        "COL_3" = THAILAND;
        "COL_4" = 5000;
        "COL_5" = No;
    },
    {
        "COL_1" = Peter;
        "COL_2" = 01/27/13;
        "COL_3" = US;
        "COL_4" = 4000;
        "COL_5" = No;
    }
 })
All dictionaries in the array have the same keys. I want to replace the existing keys with a new set of keys that will come from a NSArray. The final array should be like -
NSArray *myArray
({
{
"A" = Jhon;
"B" = 01/27/13;
"C" = THAILAND;
"D" = 5000;
"E" = No;
},
{
"A" = Peter;
"B" = 01/27/13;
"C" = US;
"D" = 4000;
"E" = No;
}
})
I do not want a nested for loop in which i have to iterate overs each elements in the array and again for each dictionary, iterating over each key , to change the keys.
What I did is as follow:
NSArray *myDictFnalKeys = [NSArray arrayWithObjects:#"A",#"B",#"C",#"D",#"E",nil];  // Here we have set our own keys which will replace the existing keys .
NSMutableArray *myNewArray = [[[NSMutableArray alloc] init] autorelease]; //create a new mutable dictionary
for (id myArrayInstance in array) {
            NSDictionary *myNewDict = [[NSDictionary alloc] initWithObjects:[myArrayInstance allObjects] forKeys:myDictFnalKeys]; // copy the object values from old dictionary and keys from the new array.
            [myNewArray addObject:myNewDict];
    }
The problem is the values for the dictionaries are not coming in proper order. [myArrayInstance allObjects] is not returning the proper order so the final array is not in proper order. Its coming like-
NSMutableArray *newArray
({
    {
        A = "01/27/13";
        B = No;
        C = Jhon;
        D = 5000;
        E = THAILAND;
    },
    {
        A = "01/27/13";
        B = No;
        C = Peter;
        D = 4000;
        E = US;
    }
})

You're almost there, the only issue is the call to allObjects which as you found returns the objects in some arbitrary order. Instead define an array of your original keys:
NSArray *originalKeys = #[#"COL_1", #"COL_2", #"COL_3", #"COL_4", #"COL_5"];
where the elements are in the same order as the replacement in your myDictFnalKeys. Now replace the call to allObjects with:
[myDict objectsForKeys:originalKeys notFoundMarker:NSNull.null]
This will return an array of objects matching the keys in order found in originalKeys (if a key is missing then the result array will contain whatever notFoundMarker is - NSNull.null in this case).
Do that and your code will work.

You can use 'objectsForKeys:notFoundMarker:' for getting the values in the requested order. Pass [NSNULL null] as the second argument. (This really does not matter, all the values are present in the dictionary and you are not trying get the values for a undefined key.)

Related

Can't clear/reset NSMutableSet?

This is what I'm trying to do. Get 7 random, non-repeating numbers each time my viewDidLoad starts. I got it to create the randoms, but I've been trying to clear the NSMutableSet when it loads to get a fresh set and I'm having trouble. The NSLog is clearly showing nothing is in the NSMutableSet, but it always comes up with the same numbers in the same order?
// Create set
NSMutableSet *mySet = [NSMutableSet setWithCapacity:6];
// Clear set
NSMutableSet *mutableSet = [NSMutableSet setWithSet:mySet];
[mutableSet removeAllObjects];
mySet = mutableSet;
NSLog(#"mutableSet: %#", mutableSet); // Shows nothing
NSLog(#"mySet: %#", mySet); // Shows nothing
// Assign random numbers to the set
while([mySet count]<=6){
int Randnum = arc4random() % 7+1;
[mySet addObject:[NSNumber numberWithInt:Randnum]];
}
NSLog(#"mySet1: %#", mySet); // Always shows 5,1,6,2,7,3,4 ???
An NS(Mutable)Set is an unordered collection, it does not preserve the order of the elements as they were inserted. So your output only shows that the set contains the
numbers from 1 to 7.
You have different options to get your expected output.
Use an NSMutableOrderedSet instead.
Use a set to keep track of the numbers that already occurred, but store the
numbers also in an array:
NSMutableArray *numbers = [NSMutableArray array];
NSMutableSet *mySet = [NSMutableSet set];
while ([numbers count] < 6) {
NSNumber *randNum = #(arc4random_uniform(7) + 1);
if (![mySet containsObject:randNum]) {
[numbers addObject:randNum];
[mySet addObject:randNum];
}
}
NSLog(#"numbers: %#", numbers);
For a small set (like 7 numbers in your case), you could simply use an array only:
NSMutableArray *numbers = [NSMutableArray array];
while ([numbers count] < 6) {
NSNumber *randNum = #(arc4random_uniform(7) + 1);
if (![numbers containsObject:randNum]) {
[numbers addObject:randNum];
}
}
NSLog(#"numbers: %#", numbers);

Creating array of quiz questions that do not repeat

I'm trying to create a basic quiz app where the questions will not repeat. I've looked at several examples and believe I should be storing the questions in an array and then removing one from the array each time its used. I've tried the following code.
- (void)viewDidLoad
{
//The array of questions
NSMutableArray *questionArray = [[NSMutableArray alloc] initWithObjects:
[NSMutableArray arrayWithObjects:#"First Question",#"Answer A", nil],
[NSMutableArray arrayWithObjects:#"Second Quesiton",#"AnswerA",#"AnswerB", nil],
nil];
//remove used question from array
for (int i = questionArray.count; i>=0; --i) {
_questions = [questionArray objectAtIndex:arc4random() % questionArray.count];
[questionArray exchangeObjectAtIndex:i withObjectAtIndex:_questions];
}
//use array object
self.lblQuestion.text = [_questions objectAtIndex:0];
[self.btnA setTitle:[_questions objectAtIndex:1] forState:UIControlStateNormal];
[super viewDidLoad];
}
I'm getting the following warning:
Incompatible pointer to integer conversion sending NSMutableArray*_strong to parameter of type 'NSUInteger'
I take it this means I shouldn't be using another array to store the random question as I can't use this to remove the question from the array. However I don't know how else to do this?
Am I completely misunderstanding how I should go about this?
Since your goal here is to get non-repeating questions...
I believe that instead of removing the question you have already used, you should SHUFFLE your array at the beginning and then loop through the array one index at a time using a simple counter.
I hope you can find this piece of code helpful -- give it a shot:
-(NSMutableArray *)shuffleArray:(NSMutableArray *)anArray
NSUInteger count = [anArray count];
for (NSUInteger i = 0; i < count; ++i)
{
int nElements = count - i;
int n = (arc4random() % nElements) + i;
[anArray exchangeObjectAtIndex:i withObjectAtIndex:n];
}
return anArray;
}
-(void)viewDidLoad
{
//The array of questions
NSMutableArray *questionArray = [[NSMutableArray alloc] initWithObjects:
[NSMutableArray arrayWithObjects:#"First Question",#"Answer A", nil],
[NSMutableArray arrayWithObjects:#"Second Quesiton",#"AnswerA",#"AnswerB", nil],
nil];
//Shuffle the question array -- Now all indexes are shuffled and Random
questionArray = [self shuffleArray:questionArray];
//Every time you want to move to the next question, all you have to do is connect a button to the nextIndex action and let it do all the work!
//Use the nextIndex method to initialise -- we call it manually the first time so things would get going and something is displayed -- you can remove the line below if you want it to initialise on first button click! Your call the shots sir!
[self nextIndex];
[super viewDidLoad];
}
//Edit -- This method shows how to change question array index using a method
int currentIndex = 0;
-(IBAction)nextIndex
{
if ( currentIndex == [questionArray count] )
{
currentIndex = 0; //Resets the var when getting to the final Index
//The above line will result in a question loop -- meaning if you arrive at the last question, the next question will be the first! Pacman mode!
//If you want to stop at the last question just change the above line to return; and you're all set!
}
//Set _questions object to the current Index Array element
_questions = [questionArray objectAtIndex:currentIndex];
//Increment currentIndex for next use
currentIndex++;
//use the array object to set your objects' values
self.lblQuestion.text = [_questions objectAtIndex:0];
[self.btnA setTitle:[_questions objectAtIndex:1] forState:UIControlStateNormal];
}
You will end up having totally different questions that are shuffled every time.
I hope you find this helpful.

Searching for Multiple Items in An NSArray

I have an NSArray and a lot of the values have the same values (i know this isn't the best way to do an array). How can i search for a string within the array and have it return me an array of indexes. For example if i wanted to search the array for "DJ Ez", how can i have it so it returns all the indexes where the index is equal to that string? So far i have tried this:
do {
isTheObjectThere = [array containsObject: #"DJ Ez"];
if(isTheObjectThere == true){
indexOfTheObject = [array indexOfObject: #"DJ Ez"];
[arrayOfIndexes addObject:[NSNumber numberWithInt:indexOfTheObject]];
[array removeObjectAtIndex:indexOfTheObject];
NSLog(#"%#", [indexesForAll objectAtIndex:intCtrl]);
hasFinished = false;
}else{
hasFinished = true;
}
intCtrl++;
} while (hasFinished == false);
However this doesn't work as when it deletes the item it messes up all the indexes for the next search. What do i do?
How about something like this:
NSIndexSet *indexes = [array indexesOfObjectsPassingTest:^BOOL(NSString *obj, NSUInteger idx, BOOL *stop) {
return [obj isEqualToString:#"DJ Ez"];
}];
That should return all of the matching indexes as an NSIndexSet, which allows you do check if specific indexes matched, or you can get the count and loop through the matching indexes however you wish.

Check for String within a String

I'm trying to compare two strings
NSString strOne = #"Cat, Dog, Cow";
NSString strTwo = #"Cow";
How do I determine if strOne contains strTwo
Try using rangeOfString:
NSRange result = [strOne rangeOfString:strTwo];
From the documentation:
Returns an NSRange structure giving the location and length in the receiver of the first occurrence of aString. Returns {NSNotFound, 0} if aString is not found or is empty (#"").
For anyone needing the code to check is a string exists within a string, here's my code thanks to fbrereto. This example checks to see if any string contained in an array of strings (stringArray) can be found within a string (myString):
int count = [stringArray count];
for (NSUInteger x = 0; x < count; ++x) {
NSRange range = [self.myString rangeOfString:[stringArray objectAtIndex:x]];
if (range.length > 0) {
// A match has been found
NSLog(#"string match: %#",[stringArray objectAtIndex:x]);
}
}
I believe this is the correct syntax for checking if the range exists (correcting response from Kendall):
range.location != NSNotFound
Gradually straying off topic, but I always explode my strings, which would mean just exploding it using your search string as a key and you can use the array count to see how many instances you have.
Just incase anyone is coming from a code language that uses "explode" to blow a string up into an array like me, I found writing my own explode function tremendously helpful, those not using "explode" are missing out:
- (NSMutableArray *) explodeString : (NSString *)myString key:(NSString*) myKey
{
NSMutableArray *myArray = [[NSMutableArray alloc] init];
NSRange nextBreak = [myString rangeOfString:myKey];
while(nextBreak.location != NSNotFound)
{
[myArray addObject: [myString substringToIndex:nextBreak.location]];
myString = [myString substringFromIndex:nextBreak.location + nextBreak.length];
nextBreak = [myString rangeOfString:myKey];
}
if(myString.length > 0)
[myArray addObject:myString];
return myArray;
}
works like this:
[self explodeString: #"John Smith|Age: 37|Account Balance: $75.00" key:#"|"];
which will return this array:
[#"John Smith", #"Age: 37", #"Account Balance: $75.00"];
This lets you quickly pull out a specific value in a tight space, Like if you have a client and you want to know how much money he has:
[[self explodeString: clientData key: pipe] objectAtIndex: 1];
or if you wanted specifically the dollar amount as a float:
[[[self explodeString: [[self explodeString: clientData key: pipe] objectAtIndex: 1] key: #": "] objectAtIndex: 2] floatValue];
anyway I find arrays way easier to work with and more flexible, so this is very helpful to me. Additionally with a little effort you could make an "explodable string" data type for your private library that lets you treat it like a string or return an index value based on the key
ExplodableString *myExplodableString;
myExplodableString.string = #"This is an explodable|string";
NSString *secondValue = [myExplodableString useKey: #"|" toGetValue: index];

NSMutableArray - Get Arrays Index Integer By Searching With A String

I have been working with NSMutableArray and have had no problems retrieving an object from an array by using objectAtIndex:int. Rather then pulling an object out of the array by an integer is their a way to get the index position by searching the array with a string.
animalOptions = [[NSMutableArray alloc] init];
//Add items
[animalOptions addObject:#"Fish"];
[animalOptions addObject:#"Bear"];
[animalOptions addObject:#"Bird"];
[animalOptions addObject:#"Cow"];
[animalOptions addObject:#"Sheep"];
NSString * buttonTitle = [animalOptions objectAtIndex:1];
// RETURNS BEAR
int * objectIndex = [animalOptions object:#"Bear"];
// THIS IS WHAT I NEED HELP WITH, PULLING AN INDEX INTEGER WITH A STRING (ex: Bear)
Hopefully this makes sense, and there is an answer out there, I have been unable to research online and find anything through google or apple's class references.
You can use the indexOfObject: method from NSArray:
NSUInteger index = [animalOptions indexOfObject:#"Bear"];
If there are duplicate entries then the lowest index of that object is returned. For more information, take a look at the docs.
you can use [array indexOfObject:object] which will return the index of that object, now with the way you are wanting to do it, it might not w ork since the string you are specifing is not the actual string object in the array doing this however will def work
NSString * buttonTitle = [animalOptions objectAtIndex:1];// RETURNS BEARint
objectIndex = [animalOptions indexOfObject:buttonTitle] //this will return 1

Resources