I've made a function to perform a calculation against four fields. Then outputs the that calculation to a receiver field.
The math is fairly simply in concept.
The receiver field is the remainder of the lowest int from the next lowest int.
For instance the app reads values 2, 5 , 6, 8 from user input.
Receiver field should equal(3)
I have implemented NSSet to remove any duplicates than re-stack the set into an array for ease of reading and the values and custom control.
The math section of the function seems like over kill. Is there a more elegant way to perform this other than what I have built? It works it's just ugly and probably not the correct path.
Any help is appreciated.
// set of strings populated from a sibling View so i used a singleton to sync.
NSArray *myArray = [[NSArray alloc] initWithObjects:[StringLinker sharedManager].singcol1Row1String,
[StringLinker sharedManager].singcol1Row2String,
[StringLinker sharedManager].singcol1Row3String,
[StringLinker sharedManager].singcol1Row4String,nil];
NSSet *set = [NSSet setWithArray:myArray];
NSLog(#"mySet count: %d", [set count]);
NSMutableArray *newArray = [NSMutableArray arrayWithArray:[set allObjects]];
// define locals
int i;
int tempV;
id *objects;
int v1Col1=0;
int v2Col1=0;
int v3Col1=0;
int v4Col1=0;
// create helpers
NSUInteger count = [newArray count];
objects = malloc(sizeof(id) * count);
[newArray getObjects:objects];
// check the correct id and location
for (i = 0; i < [newArray count]; i++) {
tempV = [[newArray objectAtIndex:i]intValue];
NSLog(#"current objectAtIndex = %i id = %i",i,tempV);
}
NSLog(#"count of new Array = %d",count);
// assign our controlled items. and make string into a Value
if (count >= 1) { v1Col1 = [[newArray objectAtIndex:0]intValue];}
if (count >= 2) { v2Col1 = [[newArray objectAtIndex:1]intValue];}
if (count >= 3) { v3Col1 = [[newArray objectAtIndex:2]intValue];}
if (count >= 4) { v4Col1 = [[newArray objectAtIndex:3]intValue];}
// then do raw calculations
if ( count ==2) {
if (v1Col1 < v2Col1) { _master1PinsCol1 = v2Col1 - v1Col1;}
if (v2Col1 < v1Col1) { _master1PinsCol1 = v1Col1 - v2Col1;}
}
if ( count ==3) {
if ((v1Col1 < v2Col1) && (v2Col1 < v3Col1)) { _master1PinsCol1 = v2Col1 - v1Col1;}
if ((v1Col1 < v2Col1) && (v3Col1 > v2Col1)) { _master1PinsCol1 = v2Col1 - v1Col1;}
if ((v1Col1 < v2Col1) && (v3Col1 < v2Col1)) { _master1PinsCol1 = v3Col1 - v1Col1;}
if ((v2Col1 < v1Col1) && (v1Col1 < v3Col1)) { _master1PinsCol1 = v1Col1 - v2Col1;}
if ((v2Col1 < v3Col1) && (v3Col1 < v1Col1)) { _master1PinsCol1 = v3Col1 - v2Col1;}
}
if (count >=4){
if ((v1Col1 < v2Col1) && (v1Col1 < v3Col1) && (v1Col1 < v4Col1)) {
if ((v2Col1 < v3Col1) && (v2Col1 < v4Col1)) {_master1PinsCol1 = v2Col1-v1Col1;}
if ((v3Col1 < v2Col1) && (v3Col1 < v4Col1)) {_master1PinsCol1 = v3Col1-v1Col1;}
if ((v4Col1 < v2Col1) && (v4Col1 < v3Col1)) {_master1PinsCol1 = v4Col1-v1Col1;}
}
if ((v2Col1 < v1Col1) && (v2Col1 < v3Col1) && (v2Col1 < v4Col1)) {
if ((v1Col1 < v3Col1) && (v1Col1 < v4Col1)) {_master1PinsCol1 = v1Col1-v2Col1;}
if ((v3Col1 < v1Col1) && (v3Col1 < v4Col1)) {_master1PinsCol1 = v3Col1-v2Col1;}
if ((v4Col1 < v1Col1) && (v4Col1 < v3Col1)) {_master1PinsCol1 = v4Col1-v2Col1;}
}
if ((v3Col1 < v1Col1) && (v3Col1 < v2Col1) && (v3Col1 < v4Col1)) {
if ((v1Col1 < v2Col1) && (v1Col1 < v4Col1)) {_master1PinsCol1 = v1Col1-v3Col1;}
if ((v2Col1 < v1Col1) && (v2Col1 < v4Col1)) {_master1PinsCol1 = v2Col1-v3Col1;}
if ((v4Col1 < v1Col1) && (v4Col1 < v2Col1)) {_master1PinsCol1 = v4Col1-v3Col1;}
}
if ((v4Col1 < v1Col1) && (v4Col1 < v2Col1) && (v4Col1 < v3Col1)) {
if ((v1Col1 < v2Col1) && (v1Col1 < v3Col1)) {_master1PinsCol1 = v1Col1-v4Col1;}
if ((v2Col1 < v1Col1) && (v2Col1 < v3Col1)) {_master1PinsCol1 = v2Col1-v4Col1;}
if ((v3Col1 < v1Col1) && (v3Col1 < v2Col1)) {_master1PinsCol1 = v3Col1-v4Col1;}
}
}
NSLog(#"***********************************Col1 Master1 = %.0f",_master1PinsCol1);
Your code has a lot of potential in saving method calls and objects. Also, it seems you were leaking memory: you malloc'd but never free'd, and your myArray wasn't released. Here's how I would do it:
// Get instance once, save three method calls.
StringLinker *linker = [StringLinker sharedManager];
// Initialize set with the objects. Convert them to NSNumbers, we need
// to have the numbers parsed later on anyway. Doing it now makes
// sorting easier.
NSSet *set = [NSSet setWithObjects:
[NSNumber numberWithInt:[linker.singcol1Row1String intValue]],
[NSNumber numberWithInt:[linker.singcol1Row2String intValue]],
[NSNumber numberWithInt:[linker.singcol1Row3String intValue]],
[NSNumber numberWithInt:[linker.singcol1Row4String intValue]],
nil
];
// Sanity check.
if ([set count] < 2) {
// Error handling goes here. For example, if there's only one
// element, can that be used as value for _master1PinsCol1 ?
return;
}
// Get mutable array of distinct objects...
NSMutableArray *array = [[set allObjects] mutableCopy];
// ... and sort it.
[array sortUsingSelector:#selector(compare:)];
// Calculate the value by subtracting the smaller number from the
// bigger number.
_master1PinsCol1 = [[array objectAtIndex:1] intValue]
- [[array objectAtIndex:0] intVale];
// Release the mutable copy.
[array release];
Related
I have two NSMutableArrays. Each contains a custom word object in it. Custom word has 2 properties text and frequency. Now I want to combine these two arrays in such a way that, if these two arrays has same text in it, then it should compare the frequency of those two text and select the highest frequency of the two. And also it should remove the duplicates from the array.
I tried every logic for this but was not able to do this. Can any body help me with the logic for this. Following the code. But it should also remove the duplicates.
for (int i = 0; i < [array count]; i++) {
for (int j = 0; j < [array count]; j++) {
if ([[[array objectAtIndex:i]firstWord] isEqualToString:[[array objectAtIndex:j] firstWord]]) {
if ([[array objectAtIndex:i] frequency] < [[array objectAtIndex:j] frequency]) {
CustomWordFrequency *word = [array objectAtIndex:i];
word.frequency = [[array objectAtIndex:j] frequency];
[array replaceObjectAtIndex:i withObject:word];
}
}
}
}
Combine the two arrays.
Sort the resulting array by text ASC, frequency DESC
Loop through the array
a. Look at the next item in the array. If the text is the same as the current word, remove it from the array. If it's different, continue looping.
NSArray *combined = [firstArray arrayByAddingObjectsFromArray:secondArray];
[combined sortUsingComparator:^(id firstObject, id secondObject) {
NSComparisonResult *result = [firstObject.text compare:secondObject.text];
if (result == NSOrderedAscending) return NSOrderedAscending;
if (result == NSOrderedDescending) return NSOrderedDescending;
if (result == NSOrderedSame) {
result = [firstObject.frequency compare:secondObject.frequency];
if (result == NSOrderedAscending) return NSOrderedDescending;
if (result == NSOrderedDescending) return NSOrderedAscending;
if (result == NSOrderedSame) return NSOrderedSame;
}
}];
for (int i = 0; i < [combined count] - 2; ++i) {
CustomWordFrequency *word = [combined objectAtIndex:i];
int j = i + 1;
while ([word.text compare:[combined objectAtIndex:j].text == NSOrderedSame) {
[combined removeObjectAtIndex:j];
j++;
if (j == [combined count]) {break;}
}
if (i >= [combined count] - 2) {break;} // the count keeps changing so check here
}
NSMutableArray *combinedArray = [[NSMutableArray alloc] init];
BOOL flagForMatchFound = FALSE;
for(CustomWordFrequency *firstWord in firstArray)
{
flagForMatchFound = FALSE;
for(CustomWordFrequency *secondWord in secondArray)
{
if([firstWord.firstWord isEqualToString:secondWord.firstWord])
{
if(firstWord.frequency >= secondWord.frequency)
{
[combinedArray addObject:firstWord];
flagForMatchFound = TRUE;
}
else
[combinedArray addObject:secondWord];
}
else
{
if(!flagForMatchFound)
[combinedArray addObject:secondWord];
}
}
}
I have a for loop running on string length. the first loop looks for a character common in the second loop. I want to save the index of nameString that is common in an array or a string. Please help. Code is mentioned below.
for (int i=0; i < nameString.length; i++) {
char currentLetter = [nameString characterAtIndex:i];
for (int j=0; j < partnersNameString.length; j++) {
if (currentLetter == [partnersNameString characterAtIndex:j]) {
NSRange range;
range.length=1;
range.location=j;
[partnersNameString replaceCharactersInRange:range withString:#""];
calculateField.text = partnersNameString;
}
}
}
There are several ways to go about doing what you are looking for: you can use a "plain" C array with a count, or you can use an NSMutableArray with wrappers.
The first way would look like this:
NSUInteger indexes[MAX_LENGTH];
NSUInteger lastIndex = 0;
for (int i=0; i < nameString.length; i++) {
char currentLetter = [nameString characterAtIndex:i];
for (int j=0; j < partnersNameString.length; j++) {
if (currentLetter == [partnersNameString characterAtIndex:j]) {
indexes[lastIndex++] = i;
// Go through the rest of your code
...
}
}
}
for (NSUInteger i = 0 ; i != lastIndex ; i++) {
NSLog(#"Found match at index %u", indexes[i]);
}
The second way looks similar, except now you need to use NSNumber to wrap the data going into NSMutableArray:
NSMutableArray *indexes = [NSMutableArray array];
for (int i=0; i < nameString.length; i++) {
char currentLetter = [nameString characterAtIndex:i];
for (int j=0; j < partnersNameString.length; j++) {
if (currentLetter == [partnersNameString characterAtIndex:j]) {
[indexes addObject[NSNumber numberWithInt:i]];
// Go through the rest of your code
...
}
}
}
for (NSNumber in indexes) {
NSLog(#"Found match at index %i", [[indexes objectAtIndex:i] intValue]);
}
You can use NSMutablearray for that
NSMutableArray myArray = [NSMutableArray new];
for (int i=0; i < nameString.length; i++) {
char currentLetter = [nameString characterAtIndex:i];
for (int j=0; j < partnersNameString.length; j++) {
if (currentLetter == [partnersNameString characterAtIndex:j]) {
//And add it here
[myArray addObject:currentLetter];
NSRange range;
range.length=1;
range.location=j;
[partnersNameString replaceCharactersInRange:range withString:#""];
calculateField.text = partnersNameString;
}
}
}
[myArray addObject:[NSNumber numberWithInt:i]];
Here i used this code to view the next value in the array,
-(IBAction)changenext
{
static int j = 0;
if (j >arcount)
{
j = 0;
}
lb1.text=[NSString stringWithFormat:[artext objectAtIndex:j]];
imager.image=[arimage objectAtIndex:j];
aplayer=[[AVAudioPlayer alloc]initWithData:[arsound objectAtIndex:j] error:nil];
j++;
}
How to view the previous array value by other button click?Please help me to solve..
-(IBAction)change_next_or_prev:(id)sender
{
static int j = 0;
if(sender == btnNext)
j++;
else if(sender == btnPrev)
j--;
if (j >= arcount)
{
j = 0;
}
else if(j < 0)
{
j = arcount - 1;
}
lb1.text=[NSString stringWithFormat:[artext objectAtIndex:j]];
imager.image=[arimage objectAtIndex:j];
aplayer=[[AVAudioPlayer alloc]initWithData:[arsound objectAtIndex:j] error:nil];
}
link both button to the same action.
-(IBAction)changeprev
{
static int j = arcount;
if (j < 0)
{
j = arcount;
}
lb1.text=[NSString stringWithFormat:[artext objectAtIndex:j]];
imager.image=[arimage objectAtIndex:j];
aplayer=[[AVAudioPlayer alloc]initWithData:[arsound objectAtIndex:j] error:nil];
j--;
}
Can I transform this loop in a while loop ?
int i=0;
for (NSDictionnary *crossArrayDictionnary in (NSArray *)mainArray) {
//some code...
i++;
if (i>=50) {
break;
}
}
Thanks,
This should do the trick:
NSInteger max, i = 0;
max = [mainArray count] < 50 ? [mainArray count] : 50;
while (i < max) {
NSDictionary *crossArrayDictionnary = [mainArray objectAtIndex:i];
// You code here.
i++;
}
NSEnumerator *enumerator = [mainArray objectEnumerator];
NSDictionary *crossArrayDictionnary = nil;
while ((crossArrayDictionnary = [enumerator nextObject])) {
//some code...
i++;
if (i>=50) {
break;
}
}
As rckoenes said,
Minor change.
NSInteger i = 0;
while (i < 50 && [itemsMutable cout] >= i) {
NSDictionary *crossArrayDictionnary = [itemsMutable objectAtIndex:i];
// You code here.
i++;
}
don't know objective-c, but something like this:
int i=0;
while (i < 50 && i < [mainArray count]) {
NSDictionary *crossArrayDictionnary = [mainArray objectAtIndex:i];
//some code...
i++;
}
(code below regarding my question)
Per this stack overflow question I used Pegolon's approach to generating all possible permutations of a group of characters inside an NSString. However, I am now trying to get it to not just generate an ANAGRAM which is all permutations of the same length, but all possible combinations (any length) of the characters in a string.
Would anyone know how i would alter the following code to get it to do this? This is much like: Generate All Permutations of All Lengths -- but (for fear of them needing answer to homework) they did not leave code. I have a sample of what I thought would do it at the bottom of this post... but it did not.
So, the code, as is, generates the, teh, hte, het, eth and eht when given THE.
What I need is along the lines of: t,h,e,th,ht,te,he (etc) in addition to the above 3 character combinations.
How would I change this, please. (ps: There are two methods in this. I added allPermutationsArrayofStrings in order to get the results back as strings, like I want them, not just an array of characters in another array). I am assuming the magic would happen in pc_next_permutation anyway -- but thought I would mention it.
In NSArray+Permutation.h
#import <Foundation/Foundation.h>
#interface NSArray(Permutation)
- (NSArray *)allPermutationsArrayofArrays;
- (NSArray *)allPermutationsArrayofStrings;
#end
in NSArray+Permutation.m:
#define MAX_PERMUTATION_COUNT 20000
NSInteger *pc_next_permutation(NSInteger *perm, const NSInteger size);
NSInteger *pc_next_permutation(NSInteger *perm, const NSInteger size)
{
// slide down the array looking for where we're smaller than the next guy
NSInteger pos1;
for (pos1 = size - 1; perm[pos1] >= perm[pos1 + 1] && pos1 > -1; --pos1);
// if this doesn't occur, we've finished our permutations
// the array is reversed: (1, 2, 3, 4) => (4, 3, 2, 1)
if (pos1 == -1)
return NULL;
assert(pos1 >= 0 && pos1 <= size);
NSInteger pos2;
// slide down the array looking for a bigger number than what we found before
for (pos2 = size; perm[pos2] <= perm[pos1] && pos2 > 0; --pos2);
assert(pos2 >= 0 && pos2 <= size);
// swap them
NSInteger tmp = perm[pos1]; perm[pos1] = perm[pos2]; perm[pos2] = tmp;
// now reverse the elements in between by swapping the ends
for (++pos1, pos2 = size; pos1 < pos2; ++pos1, --pos2) {
assert(pos1 >= 0 && pos1 <= size);
assert(pos2 >= 0 && pos2 <= size);
tmp = perm[pos1]; perm[pos1] = perm[pos2]; perm[pos2] = tmp;
}
return perm;
}
#implementation NSArray(Permutation)
- (NSArray *)allPermutationsArrayofArrays
{
NSInteger size = [self count];
NSInteger *perm = malloc(size * sizeof(NSInteger));
for (NSInteger idx = 0; idx < size; ++idx)
perm[idx] = idx;
NSInteger permutationCount = 0;
--size;
NSMutableArray *perms = [NSMutableArray array];
do {
NSMutableArray *newPerm = [NSMutableArray array];
for (NSInteger i = 0; i <= size; ++i)
[newPerm addObject:[self objectAtIndex:perm[i]]];
[perms addObject:newPerm];
} while ((perm = pc_next_permutation(perm, size)) && ++permutationCount < MAX_PERMUTATION_COUNT);
free(perm);
return perms;
}
- (NSArray *)allPermutationsArrayofStrings
{
NSInteger size = [self count];
NSInteger *perm = malloc(size * sizeof(NSInteger));
for (NSInteger idx = 0; idx < size; ++idx)
perm[idx] = idx;
NSInteger permutationCount = 0;
--size;
NSMutableArray *perms = [NSMutableArray array];
do {
NSMutableString *newPerm = [[[NSMutableString alloc]initWithString:#"" ]autorelease];
for (NSInteger i = 0; i <= size; ++i)
{
[newPerm appendString:[self objectAtIndex:perm[i]]];
}
[perms addObject:newPerm];
} while ((perm = pc_next_permutation(perm, size)) && ++permutationCount < MAX_PERMUTATION_COUNT);
free(perm);
return perms;
}
#end
My code that I thought would fix this:
for ( NSInteger i = 1; i <= theCount; i++) {
NSRange theRange2;
theRange2.location = 0;
theRange2.length = i;
NSLog(#"Location: %i (len: %i) is: '%#'",theRange2.location,theRange2.length,[array subarrayWithRange:theRange2]);
NSArray *allWordsForThisLength = [[array subarrayWithRange:theRange2] allPermutationsArrayofStrings];
for (NSMutableString *theString in allWordsForThisLength)
{
NSLog(#"Adding %# as a possible word",theString);
[allWords addObject:theString];
}
I know it would not be the most efficient..but I was trying to test.
This is what I got:
2011-07-07 14:02:19.684 TA[63623:207] Total letters in word: 3
2011-07-07 14:02:19.685 TA[63623:207] Location: 0 (len: 1) is: '(
t
)'
2011-07-07 14:02:19.685 TA[63623:207] Adding t as a possible word
2011-07-07 14:02:19.686 TA[63623:207] Location: 0 (len: 2) is: '(
t,
h
)'
2011-07-07 14:02:19.686 TA[63623:207] Adding th as a possible word
2011-07-07 14:02:19.687 TA[63623:207] Adding ht as a possible word
2011-07-07 14:02:19.688 TA[63623:207] Location: 0 (len: 3) is: '(
t,
h,
e
)'
2011-07-07 14:02:19.688 TA[63623:207] Adding the as a possible word
2011-07-07 14:02:19.689 TA[63623:207] Adding teh as a possible word
2011-07-07 14:02:19.690 TA[63623:207] Adding hte as a possible word
2011-07-07 14:02:19.691 TA[63623:207] Adding het as a possible word
2011-07-07 14:02:19.691 TA[63623:207] Adding eth as a possible word
2011-07-07 14:02:19.692 TA[63623:207] Adding eht as a possible word
As you can see, no one or two letter words -- I am pulling my hair out! (and I don't have much to spare!)
An easy thing to do would be to take all subsets of size k and use the code you have to generate all permutations of the subset. This is easy, but not the most efficient.
Here's a better approach. You are generating permutations lexicographically in the first routine:
1234
1243
1324
1342
1423
...
Each time you call NSInteger *pc_next_permutation(NSInteger *perm, const NSInteger size), you get the next permutation in lex order by finding the correct position to change. When you do that, truncate from the spot you changed to get the following:
1234 123 12 1
1243 124
1324 132 13
1342 134
1423 142 14
1432 143
2143 214 21 2
...
I hope the idea is clear. Here's one way to implement this (in Objective C-like pseudocode).
-(NSMutableArray *)nextPerms:(Perm *)word {
int N = word.length;
for (int i=N-1; i > 0; ++i) {
if (word[i-1] < word[i]) {
break;
} else if (i==1) {
i = 0;
}
}
// At this point, i-1 is the leftmost position that will change
if (i == 0) {
return nil;
}
i = i-1;
// At this point, i is the leftmost position that will change
Perm *nextWord = word;
for (int j=1; j <= N-i; ++j) {
nextWord[i+j] = word[N-j];
}
nextWord[i] = nextWord[i+1];
nextWord[i+1] = word[i];
// At this point, nextPerm is the next permutation in lexicographic order.
NSMutableArray *permList = [[NSMutableArray alloc] init];
for (int j=i; j<N; ++j) {
[permList addObject:[nextWord subwordWithRange:NSMakeRange(0,i)]];
}
return [permList autorelease];
}
This will return an array with the partial permutations as described above. The input for nextPerms should be the lastObject of the output of nextPerms.
Okay,
Down and dirty for now, however, this is what I did...
I changed the NSArray+Permutations.m to be as follows:
- (NSArray *)allPermutationsArrayofStrings
{
NSInteger size = [self count];
NSInteger *perm = malloc(size * sizeof(NSInteger));
for (NSInteger idx = 0; idx < size; ++idx)
perm[idx] = idx;
NSInteger permutationCount = 0;
--size;
NSMutableArray *perms = [NSMutableArray array];
NSMutableDictionary *permsDict = [[NSMutableDictionary alloc] init];
do {
NSMutableString *newPerm = [[[NSMutableString alloc]initWithString:#"" ]autorelease];
for (NSInteger i = 0; i <= size; ++i)
{
[newPerm appendString:[self objectAtIndex:perm[i]]];
}
if ([permsDict objectForKey:newPerm] == nil)
{
[permsDict setObject:#"1" forKey:newPerm];
[perms addObject:newPerm];
}
for (NSInteger i = 1; i <= [newPerm length]; ++i)
{
NSRange theRange;
theRange.location = 0;
theRange.length = i;
if ([permsDict objectForKey:[newPerm substringToIndex:i]] == nil)
{
[permsDict setObject:#"1" forKey:[newPerm substringToIndex:i]];
[perms addObject:[newPerm substringToIndex:i]];
}
}
} while ((perm = pc_next_permutation(perm, size)) && ++permutationCount < MAX_PERMUTATION_COUNT);
free(perm);
[permsDict release];
return perms;
}
The major changes were the idea #PengOne had... Return the resulting lexically changed string but also shorten it by 1 character at a time and add that to the returned array if it did not exist already.
I chose to be "cheap" about it and keep track using a NSMutableDictionary. So if the lexically changed string was not listed in the dictionary, it was added.
Is that more-or-less what you thought I should do, #PengOne?
WAY faster than adding them all and dealing with the resulting duplicates later -- and I think it works like I need it to.