I have an array of integers (NSMutable array to be exact), now i want the array to have unique elements, but there is a catch.
Condition-1. If there are 2 (even number of )elements that are similar then both the elements need to be deleted.
Condition-2. If there are 3(odd number of) elements then only 1 element shall remain in the array.
am having a bit of a problem trying to solve it.
I have tried to loop around the array with 2 temporary variables
for(int i =1;i<[tagArray count];i++){
int temp1 = [[tagArray objectAtIndex:i] intValue];
int temp2 = [[tagArray objectAtIndex:i-1] intValue];
if(temp1==temp2){
[tagArray removeObjectIdenticalTo:[tagArray objectAtIndex:i]];
[tagArray removeObjectAtIndex:i];
NSLog(#"%#",tagArray);
}
}
This code works but, when there are a lot of elements in the array the output i get is not the desired one.
P.S- the array is already being filled up randomly so i took the liberty of sorting it first.
1 more thing. please dont say abt set, i want unique elements but when i use SET see condition1 and 2. i cant perform those.
sort array (by ascending or descending intValue)
loop through each element (from 0 to N-1) and count number of previous equals elements (write it to equalNumbersCount).
After current number becomes not equal to previous, look at equalNumberCount and remove necessary number of elements (if this count is > 1 and even, remove all, if it's odd, remove only equalNumberCount - 1 previous elements)
Reset equalNumberCount to 0.
Something like this. Tested and seems to work fine:
NSMutableArray *arr = [#[#1, #4, #4, #2, #2, #3, #3, #3, #4, #4, #5] mutableCopy];
arr = [[arr sortedArrayWithOptions:NSSortStable usingComparator:^NSComparisonResult(id obj1, id obj2) {
return [obj1 compare:obj2];
}] mutableCopy];
uint countOfEqualElements = 1;
for (uint i = 1; i < arr.count; i++) {
NSNumber *n1 = arr[i-1];
NSNumber *n2 = arr[i];
if ( [n2 isEqualToNumber:n1]) {
countOfEqualElements++;
}
else if (countOfEqualElements > 1){
uint numToRemove = countOfEqualElements % 2 == 0 ? countOfEqualElements : countOfEqualElements - 1;
countOfEqualElements = 1;
NSRange r;
r.length = numToRemove;
r.location = i - numToRemove;
NSIndexSet * is = [NSIndexSet indexSetWithIndexesInRange:r];
[arr removeObjectsAtIndexes:is];
i -= numToRemove;
}
}
Though I've not tested with other elements yet, at present I think this might atleast interest you.
NSArray *localArray = #[#"1",#"23",#"2",#"3",#"4",#"5",#"5",#"9",#"1",#"11",#"10",#"1",#"23",#"3"];
NSCountedSet *countedSet= [[NSCountedSet alloc] initWithArray:localArray];
NSMutableArray *arrayToCheck = [localArray mutableCopy];
for (id obj in [localArray mutableCopy])
{
if([countedSet countForObject:obj]==2)
{
[arrayToCheck removeObject:obj inRange:NSMakeRange([[localArray mutableCopy] indexOfObject:obj], [arrayToCheck count]-[[localArray mutableCopy] indexOfObject:obj])];
}
else if ([countedSet countForObject:obj]==3)
{
[arrayToCheck removeObject:obj inRange:NSMakeRange([[localArray mutableCopy] indexOfObject:obj], [arrayToCheck count]-[[localArray mutableCopy] indexOfObject:obj])];
[arrayToCheck addObject:obj];
}
}
localArray = [NSArray arrayWithArray:arrayToCheck];
NSLog(#" array is %#",localArray);
Related
Question:
Find the value of K in myInterViewArray without any messages/calls
I was given this hint:
The numbers in the array will never exceed 1-9.
NSArray *myInterViewArray = #[#2,#1,#3,#9,#9,#8,#7];
Example:
If you send 3, the array will return the 3 biggest values in myInterViewArray * 3. So in the example below, K = 9 + 9 + 8.
--
I was asked this question a while back in an interview and was completely stumped. The first solution that I could think of looked something like this:
Interview Test Array:
[self findingK:myInterViewArray abc:3];
-(int)findingK:(NSArray *)myArray abc:(int)k{ // With Reverse Object Enumerator
myArray = [[[myArray sortedArrayUsingSelector:#selector(compare:)] reverseObjectEnumerator] allObjects];
int tempA = 0;
for (int i = 0; i < k; i++) {
tempA += [[myArray objectAtIndex:i] intValue];
}
k = tempA;
return k;
}
But apparently that was a big no-no. They wanted me to find the value of K without using any messages. That means that I was unable to use sortedArrayUsingSelector and even reverseObjectEnumerator.
Now to the point!
I've been thinking about this for quite a while and I still can't think of an approach without messages. Does anyone have any ideas?
There is only one way to do that and that is bridging the array to CF type and then use plain C, e.g.:
NSArray *array = #[#1, #2, #3];
CFArrayRef cfArray = (__bridge CFArrayRef)(array);
NSLog(#"%#", CFArrayGetValueAtIndex(cfArray, 0));
However, if the value is a NSNumber, you will still need messages to access its numeric value.
Most likely the authors of the question didn't have a very good knowledge of the concept of messages. Maybe they thought that subscripting and property access were not messages or something else.
Using objects in Obj-C without messages is impossible. Every property access, every method call, every method initialization is done using messages.
Rereading the question, they probably wanted you to implement the algorithm without using library functions, e.g. sort (e.g. you could implement a K-heap and use that heap to find the K highest numbers in a for iteration).
I assume what is meant is that you can't mutate the original array. Otherwise, that restriction doesn't make sense.
Here's something that might work:
NSMutableArray *a = [NSMutableArray array];
for (NSNumber *num in array) {
BOOL shouldAdd = NO;
for (int i = a.count - 1; i >= k; i--) {
if ([a[i] intValue] < [num intValue]) {
shouldAdd = YES;
break;
}
}
if (shouldAdd) {
[a addObject:num];
}
}
int result = a[a.count - k];
for (int i = k; k < a.count; k++) {
result += [a[i] intValue];
}
return result;
I'm trying to figure out the best way to sort an NSMutableDictionary. I have a dictionary of Card keys (i.e. aceSpades) that store Card values (i.e. 14). I have then been using an NSMutableArray to shuffle the 52 Card keys into an array called shuffledCards. Finally I make another array from shuffledCards thats takes a portion (15) of shuffledCards and puts them into an array called computerHand.
The new array computerHand is not good enough because I need to be able to connect the Card values with the Card keys. What I really need to do is create a new NSMutableDictionary for computerHand from the array shuffledCards so that I can sort it by Card values and still be able to retrieve the Card keys.
I'm thinking I need something like this, where currentCard is the first card of the shuffedCards array:
if (currentCard == 1) {
[compHandDictionary setObject:[[highCardDictionary
valueForKey:[shuffledCards objectAtIndex:currentCard]] intValue]
forKey:[cardsShuffled objectAtIndex:currentCard]];
}
However this is not allowed because "int" to "id" is not allowed.
There might be a better way but I have not been able to find anything. Any help would be appreciated.
...
I got this to work by modifying jstevenco's answer. I created two arrays and formed a new dictionary for the computer hand of just the 15 cards. Then to sort I used:
NSArray* sortedKeys = [newDict keysSortedByValueUsingComparator: ^(id obj1, id obj2) {
if ([obj1 integerValue] > [obj2 integerValue]) {
return (NSComparisonResult)NSOrderedAscending;
}
if ([obj1 integerValue] < [obj2 integerValue]) {
return (NSComparisonResult)NSOrderedDescending;
}
return (NSComparisonResult)NSOrderedSame;
}];
Thanks all!
You can sort a dictionary's keys using:
NSArray* sortedKeys = [[dict allKeys] sortedArrayUsingSelector:#selector(caseInsensitiveCompare:)];
If you then want to create a sorted array from this you can use:
NSArray* objects = [dict objectsForKeys:sortedKeys notFoundMarker:[NSNull null]];
Consider using an array of dictionaries, where each dictionary contains the name and value for a given card, for example like so:
NSArray *cards = #[#{#"name" : #"Queen", #"value" : #12},
#{#"name" : #"Jack", #"value" : #11},
#{#"name" : #"Ace", #"value" : #14},
#{#"name" : #"King", #"value" : #13}];
You could then easily sort the cards array as shown below:
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:#"value" ascending:YES];
NSArray *sortedCards = [cards sortedArrayUsingDescriptors:#[sortDescriptor]];
NSLog(#"\n\n%#\n\n", sortedCards);
Output of the NSLog statement above would be as follows:
(
{
name = Jack;
value = 11;
},
{
name = Queen;
value = 12;
},
{
name = King;
value = 13;
},
{
name = Ace;
value = 14;
}
)
To obtain an array of card names, you could then simply send a valueForKey: message to the sorted array of card dictionaries:
NSArray *sortedNames = [sortedCards valueForKey:#"name"];
NSLog(#"\n\n%#\n\n", sortedNames);
The output of the preceding NSLog statement would be:
(
Jack,
Queen,
King,
Ace
)
I have a NSMutable array with elements inserted like this:
[availableSeatsArray addObject:[NSString stringWithString:num_available]];
I want to remove the elements in the array that have values of zero or lower. I tried checking the element's value using its int value and even its string value, but it always passes the '0' element case. Console output of the array before and after below.
for (int i=0;i<[availableSeatsArray count]; i++) {
if ([[availableSeatsArray objectAtIndex:i] intValue] <= 0 || ([[availableSeatsArray objectAtIndex:i] isEqualToString:#"0"])) {
NSLog(#"Removed index: %d", [[availableSeatsArray objectAtIndex:i] intValue]);
[availableSeatsArray removeObjectAtIndex:i];
}
}
Console output:
Available array: (
"-2",
10,
5,
"-5",
0,
10,
10,
)
2012-08-14 11:13:28:002 -[dmbAddReservation viewWillAppear:] [Line 1074] Removed index: -2
2012-08-14 11:13:28:004 -[dmbAddReservation viewWillAppear:] [Line 1074] Removed index: -5
2012-08-14 11:13:28:006 -[dmbAddReservation viewWillAppear:] [Line 1083] Available array: (
10,
5,
0, // I cannot explain why this element was not removed
10,
10,
)
A couple of points.
Try using integerValue instead of intValue
Rather than store the string representation of a number in your array, just use an NSNumber instead. That's what it's for.
Avoid mutating your arrays while you iterate through them.
So you create your array with:
[availableSeatsArray addObject:[NSNumber numberWithInteger:[num_available integerValue]]];
And then you can filter them out (note I'm using the block based enumeration methods):
__block NSMutableArray *itemsToRemove;
[availableSetsArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if ([obj integerValue] == 0]) {
[itemsToRemove addObject:obj]
}
}];
// Now that you've selected which objects to remove you can actually remove them.
[availableSetsArray removeObjectsInArray:itemsToRemove];
The problem is that this approach uses a fundamentally flawed logic. It erronously doesn't remove consecutive occurrences of 0 or negative objects. The reason is, when in the for loop you check for "-5", it passes the test, then you remove it, shrinking the array, and shifting its remaining elements so that the "0" will now be in the place of the "-5". But in the for loop, you advance the loop variable (i in this case) regardless of whether an element was or wasn't removed, so now 'i' points one past the zero. And it wouldn't be checked. Solution: only increase the loop variable if there are no consecutive elements that pass your test (i. e. change the if to while):
for (int i = 0; i < [availableSeatsArray count]; i++) {
while ([[availableSeatsArray objectAtIndex:i] intValue] <= 0
|| ([[reservatiomAvailableArray objectAtIndex:i] isEqualToString:#"0"])) {
NSLog(#"Removed index: %d", [[availableSeatsArray objectAtIndex:i] intValue]);
[availableSeatsArray removeObjectAtIndex:i];
}
}
It's skipping that element because you're removing the -5 before it. i increments to the next value, and that index is now occupied by the first 10. There are probably several ways around this, but the first that comes to mind is filteredArrayUsingPredicate: (see the NSArray documentation).
I would go for NSPredicate and predicateWithBlock:. For NSMutableArray you can use filterUsingPredicate: method which will remove unneeded objects from your array without creating a new one. The following code will do it:
NSMutableArray *arr = [NSMutableArray arrayWithObjects:#"0",#"1",#"2", #"-50", nil];
NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(NSString* evaluatedObject, NSDictionary *bindings) {
return [evaluatedObject compare:#"0" options:NSNumericSearch] > 0;
}];
[arr filterUsingPredicate:predicate];
NSLog(#"%#", arr);
how can I count how many itens do I have inside of "bills"?
bills = (
{
id = 1;
name = "Cursus Nibh Venenatis";
value = "875.24";
},
{
id = 2;
name = "Elit Fusce";
value = "254.02";
}
);
I'm counting this way:
NSUInteger keyCount = [resultsDictionary count];
NSLog(#"%i", keyCount);
Thanks!
A naive solution would assume the OP wants to count bills, which happens to be an array, so the solution would be
NSLog(#"Count: %i", [[resultsDictionary objectForKey: #"bills"] count]);
However, if you have a dictionary with more than one object you want to count, then enumerating them all is the only way to go.
NSUInteger keyCount = [resultsDictionary count];
NSLog(#"%i", keyCount);
is true but also you can use [resultsDictionary allKeys]; which will return an array of keys and you can directly get its count. For more, please visit docs :v
NSMutableArray *billsArray =[[NSMutableArray alloc] init];
billsArray = [resultsDictionary valueForKey:#"bills"];//returns array
NSUInteger keyCount = [billsArray count];
NSLog(#"%i", keyCount);
I think it will be helpful to you.
NSUInteger count = [bills count]; // top level items in the dictionary
If you want to get ALL items, then you need to use block enumeration and recursively ask every dictionary what the count is and then sum. You have to write code - there is no system provided method to do this. Look at the block enumerations (ie enumerate....) in the class reference.
you can also ask each item what it is - and if "isKindOf:" a NSDictionary or NSArray, get the count, otherwise treat it as 1.
I need to pick string valur from an NSMutableArray then save it into a plist. I've builded an NSMutableArray to display infos in table View. Maximum allowed index is 8. (paste just two in example)
The problem if the String doesn't exist, I get the following error:
sDict is a dictionary for saving datas to a property list file.
the code:
- (IBAction)save:(id)sender {
(...)
NSString *One;
NSString *Two;
...etc
if ([self.smOne objectAtIndex:0])
One = [self.smOne objectAtIndex:0];
if ([self.smOne objectAtIndex:1])
Two = [self.smOne objectAtIndex:1];
...etc
if (One)
[sDict setObject:[self.smTwo objectAtIndex:0]
forKey:[UserM stringByAppendingString:One]];
[sDict setObject:[self.smThree objectAtIndex:0]
forKey:[UserS stringByAppendingString:One]];
[sDict setObject:[self.smFour objectAtIndex:0]
forKey:[UserP stringByAppendingString:One]];
if (Two)
[sDict setObject:[self.smTwo objectAtIndex:1]
forKey:[UserM stringByAppendingString:Two]];
[sDict setObject:[self.smThree objectAtIndex:1]
forKey:[UserS stringByAppendingString:Two]];
[sDict setObject:[self.smFour objectAtIndex:1]
forKey:[UserParM stringByAppendingString:Two]];
...etc
}
This code works if all objects are present, but fails if it miss one of the object at index.
I really don't know how to check properly if the object is present or not, cause code above seem's to don't works well.
I've tried with [self.smOne count] but as problem to pass as a Int or String to make conditions with.
Thanks for answer.
it looks like you're explicitly checking smOne from indices 1 through 8. But you also mentioned that the array can have up to 8. So if it's missing, say, 6, 7 and 8, you'd still be calling [smOne objectAtIndex:6], which would result in an NSRangeException being raised as 6 is out of bounds for the array.
try this instead:
int i = 0;
for ( NSString *aString in self.smOne )
{
[sDict setObject:[self.smTwo objectAtIndex:i]
forKey:[UserM stringByAppendingSting:aString]];
[sDict setObject:[self.smThree objectAtIndex:i]
forKey:[UserS stringByAppendingString:aString]];
[sDict setObject:[self.smFour objectAtIndex:i]
forKey:[UserP stringByAppendingString:aString]];
i++;
}
it'll go through each object in the smOne array and add the object into sDict regardless of how many items you have in smOne.
also, be careful with how you're generating your keys. there's the possibility that [UserM stringByAppendingSting:aString] won't always be unique.
Sorry to ask again but i have dificulties to find how to rebuild arrays from the key/string couple saved with the loop.
i've tried this:
int i = 0;
for (NSString *SMServ in [temp objectForKey:
[UserMen stringByAppendingFormat:#"%d",i]]){
NSString *SMMem[i];
SMMem[i] = [temp objectForKey:[UserMen stringByAppendingFormat:#"%d",i]];
NSArray *theArray = [ NSArray arrayWithObjects:SMMem count:i];
i++;
}
But nothing happens.
if i try with for (i = 0; i < 9; i ++) and (i + 1) instead of [i], i get same bounds errors in the first example.
thanks again for help.
Well, finally it ,works. Thanks for link to the documentation, i read too fast last time.
I'm sure this is not the cleanest way, but it works with this loop:
for (key in sDict) {
if ([sDict valueForKey:[UserMen stringByAppendingFormat:#"%d",i]]) {
tempMe = [sDict valueForKey:[UserMen stringByAppendingFormat:#"%d",i]];
if (tempMe) {
[manArray insertObject:tempMe atIndex:(0 + a)];
[bankArray insertObject:[NSString stringWithFormat:#"%d",i] atIndex:(0 + a)];
a++;
}
}
if ([sDict valueForKey:[UserSerial stringByAppendingFormat:#"%d",i]]) {
SMSer = [sDict valueForKey:[UserSerial stringByAppendingFormat:#"%d",i]];
if (SMSer) {
[serArray insertObject:SMSer atIndex:(0 + b)];
b++;
}
}
if ([sDict valueForKey:[UserPart stringByAppendingFormat:#"%d",i]]) {
SMPart = [sDict valueForKey:[UserPart stringByAppendingFormat:#"%d",i]];
if (SMPart) {
[partArray insertObject:SMPart atIndex:(0 + c)];
c++;
}
}
i++;
}