Compare and get the Index from NSMutableArray - ios

I have an array, which is a collection of arrays.
say
(
( 1, x, y, a),
( 2, m, n, o),
( 3, s, t, u, v, w)
)
If I want to get the index of m, how do I get it?
Can that be done using NSMutableArray contains:(id) ?

Check with this code:
int arrayPos = 0;
for (NSArray *tempArray in collectionArray)
{
if(tempArray containsObject:#"m")
{
int indexOfWord = [tempArray indexOfObject:#"m"];
NSlog(#"Array pos: %d Index is : %d",pos, indexOfWord);
}
pos++;
}
In the for loop you get each array that is added in the collection array. After that you are checking the existence of the word in the array. If it is present you are displaying it.
Also printing the position of array also.
The element is situated at:
NSString *str = [[collectionArrayObjectAtIndex:pos] objectAtIndex:indexOfWord];

NSArray *arrWithArr;
NSArray *arrWithM;
NSInteger arrIndex;
for (int i = 0; i< [arrWithArr count]; i++) {
if ([[arrWithArr objectAtIndex:i] containsObject:#"m"]) {
arrIndex = i; break;
}
}
NSInteger mIndex = [[arrWithArr objectAtIndex:arrIndex]indexOfObject:#"m"];

The function you're talking about, "[NSMutableArray contains:]" will tell you if object "B" exists in an array of {A, B, C}.
What you really need to do is come up a second function that does a fast enumeration through your parent array and then does the "contains" thing on the sub-arrays. If it finds "m", return "YES" and the index of that entry in the parent array.

Related

How to sort one array based on the order of its object in another array in objective-c?

I have list which is sorted by user. then I get the list from server again.
some elements might be deleted or added.
I want to sort the new array based on the sorting of the previous array then add new elements.
Example
oldElementList: [1, 4, 2, 8] ---> user set this order
newElementList: [1, 4, 3, 8]
What I want as output is: [1, 4, 8, 3]
Actually element are not numbers they are objects. and when they are gotten from server some of their property values might have changed.
My answer:
for (ElementModel *oldElement in oldElementList) {
for (ElementModel * newElement in newElementList) {
if ([newElement.number isEqualToString: oldElement.number]) {
[sortedArray addObject: newElement];
[newElementList removeObject: newElement];
break;
}
}
}
for (ElementModel *newElement in newElementList) {
[sortedArray addObject: newElement];
}
I don't think my answer is ok, I want to make it better in performance or in any other aspect that I have not considered.
Which sorting algorithm is appropriate depends very much on your data, e.g.:
- Is the data set to be sorted large (only then, a sophisticated algorithms may pay off)?
- Is the data set to be sorted completely random or presorted?
From your description it seems to me that you have a large data set (otherwise any algorithms giving the correct result would be probably fine, including your own that has a O(n^2) complexity), and that it is presorted, i.e. there are only only a few additions and deletions (otherwise it may not be so important to keep the original sorting).
If so, what about the following algorithm (sorry, it is in Swift, but could surely easily be converted to Obj-C):
let old = [1, 4, 2, 7, 8]
let new = [1, 4, 3, 8, 2]
var oldIndexed: [Int: Int] = [:]
for i in 0 ..< old.count {
oldIndexed[old[i]] = i
}
var newIndexed: [Int: Int] = [:]
for i in 0 ..< new.count {
newIndexed[new[i]] = oldIndexed[new[i]] ?? old.count
}
var resultArray: [(Int, Int)] = []
for (key, value) in newIndexed {
resultArray.append((key, value))
}
resultArray = resultArray.sorted { (first, second) -> Bool in
first.1 < second.1
}
let result = resultArray.map{ $0.0 } // Here: [1, 4, 2, 8, 3]
The idea is to give the old data elements an index, and every new data element the same index. This is done by using dictionaries, since there every element can be accessed by its key in O(1). New elements get a larger index (this could also be a counter to make it clearer). Then the new dictionary is converted back to an array, that is then sorted by its index. Eventually, the index is dropped, and the result is ready.
I guess, the complexity of this algorithm is determined by the sort function that should be optimal since it is implemented in the standard library.
EDIT:
I did not program in Obj-C for a long time, but tried it just for fun once more:
NSArray *old = #[#1, #4, #2, #7, #8];
NSArray *new = #[#1, #4, #3, #8, #2];
NSMutableDictionary *oldIndexed = [[NSMutableDictionary alloc] init];
for (int i = 0; i < old.count; i++) {
[oldIndexed setValue:[NSNumber numberWithInt: i] forKey: old[i]];
}
NSMutableDictionary *newIndexed = [[NSMutableDictionary alloc] init];
long counter = old.count;
for (int i = 0; i < old.count; i++) {
NSNumber *oldIndexOfNewValue = oldIndexed[new[i]];
NSNumber *newIndex;
if (oldIndexOfNewValue != nil) {
newIndex = oldIndexOfNewValue;
} else {
newIndex = [NSNumber numberWithLong: counter];
counter++;
}
[newIndexed setValue: newIndex forKey: new[i]];
}
NSMutableArray *resultArray = [[NSMutableArray alloc] init];
NSArray *allKeysInNewIndexed = newIndexed.allKeys;
for (int i = 0; i < allKeysInNewIndexed.count; i++) {
NSNumber *nextKey = allKeysInNewIndexed[i];
NSArray *nextPair = #[nextKey, newIndexed[nextKey]];
[resultArray addObject: nextPair];
}
NSArray *sortedResultArray;
sortedResultArray = [resultArray sortedArrayUsingComparator: ^NSComparisonResult(NSArray *first, NSArray *second) {
NSNumber *firstIndex = first[1];
NSNumber *secondIndex = second[1];
return [firstIndex compare: secondIndex];
}];
NSMutableArray * result = [[NSMutableArray alloc] init];
for (int i = 0; i < sortedResultArray.count; i++) {
[result addObject: sortedResultArray[i][0]];
}

How to get the desired dictionary result using mutable arrays in ios

I have three mutable array:
wkdatearray values like this: date from 2016-01-10 to 2016-01-16.
spentonarray values like this: 2016-01-10 to 2016-01-13.
hoursarray values like this: 7,3,4,5,1.
So, I compare the index objects of wkdatearray and spentarray like this:
for (int i = 0; i < self.wkDateArray.count; i++) {
for (int j = 0; j < self.spentonArray.count; j++) {
if ([
[self.wkDateArray objectAtIndex: i] isEqualToString: [self.spentonArray objectAtIndex: j]
]) {
NSLog(# "Matched Indexes %d %#", i, [self.wkDateArray objectAtIndex: i]);
} else {
}
}
Now I want to get the result like :
If the index value of self.wkdatearray and self.spentonarray are matched or equals then I have to set the hours array value as object for self.wkdatearray[0],[1]…[6]. like this in newsheet dictionary. Now I manually put string #"".
newSheet = [NSDictionarydictionaryWithObjectsAndKeys:strEntryID,entryID, proj,project,projID,projectId, strIssue,issue,strIssueID,issueId, strActivity,activity,strActivityId,activityId,#"",comment,#"",self.wkDateArray[0],#"",self.wkDateArray[1],#"",self.wkDateArray[2],#"",self.wkDateArray[3],#"",self.wkDateArray[4],#"",self.wkDateArray[5],#"",self.wkDateArray[6], nil];
If the index value of self.wkdatearray and self.spentonarray are not matched and not equals then the hours value like this #“‘ as object for self.wkdatearray[0].like this in newsheet dictionary. Now, I put by default object values as #""for self.wkdatearray[0...6].
Here the hours array having 5 values only.
How to do both the conditions inside the for loop? Or is there any other way to do this?
First of all make the newSheet dictionary mutable. You do not need 2 for loops.
int minIndexCount = MIN(self.wkdatearray.count, self. spentonArray.count)
we first take the min of wkdatearray.count and spentonArray.count since for example if there are only 2 items in spentonArray then if we try to use index 4 of wkdatearray then we do not have index 4 in spentonArray, meaning the primary condition that the indexes of both wkdatearray and spentonArray should be equal fails. Hence by taking min we ensure that we are only going to compare those indexes whixha re available in both wkdatearray and spentonArray.
for (int i = 0; i < minIndexCount; i++) {
if ([[self.wkDateArray objectAtIndex: i] isEqualToString: [self.spentonArray objectAtIndex: i]])
{
NSLog(# "Matched Indexes %d %#", i, [self.wkDateArray objectAt Index: i]);
[newSheet setValue:self.hoursarray[i] forKey:self.weekArray[i]]
} else {
}
}
If by "matched or equals" you mean that if the index's are the same AND the strings are matched.
for (int i = 0; i < self.wkDateArray.count; i++) {
for (int j = 0; j < self.spentonArray.count; j++) {
if (i==j && [
[self.wkDateArray objectAtIndex: i] isEqualToString: [self.spentonArray objectAtIndex: j]
]) {
NSLog(# "Matched Indexes %d %#", i, [self.wkDateArray objectAtIndex: i]);
} else {
}
}
Take note of the beginning of the if statement that has if (i==j && ...

Rearrange NSMutableArray depending on Order from 2nd Array

I have NSMutableArray stored dictionary which need to be sorted out.... sorting depend on Fields present in another array....
Example:
Array 1 ==> Red - 1, White - 2, Green - 3. Array 2 ==> Green, Red,
White
Result should be Array 3 => Green - 3, Red - 1, White - 2. (items in
Array 1 is sorted depend on Order in Array 2).
In case your first array looks like: [{#"Red": #1}, {#"White": 2}, {#"Green": 3}], the next approach should work:
NSArray* array3 = [array1 sortedArrayUsingComparator:^NSComparisonResult(NSDictionary* dict1, NSDictionary* dict2) {
NSUInteger idx1 = [array2 indexOfObject:[dict1 allKeys][0]];
NSUInteger idx2 = [array2 indexOfObject:[dict2 allKeys][0]];
if(idx1 < idx2) return NSOrderedAscending;
if(idx2 > idx1) return NSOrderedDescending;
return NSOrderedSame;
}];

Finding out NSArray/NSMutableArray changes' indices

I have a NSMutableArray oldArray. Now, at one point, this NSMutableArray object gets updated with another NSMutableArray, which may have more, less or same number of elements as the previous NSMutableArray.
I want to compare the old and the new array for changes. What I want are two NSArrays addedArray and removedArray which will contain the indices of the elements which have been added and/or removed from the old array.
This whole problem will be more clear with an example :
oldArray = {#"a",#"b",#"d",#"e",#"g"};
newArray = {#"a",#"c",#"d",#"e",#"f",#"h"};
So, here the removed objects are #"b" and #"g" at indices 1 and 4 respectively. And the objects added are #"c", #"f" and #"h" at indices 1, 4 and 5 (first objects are removed, then added).
Therefore,
removedArray = {1,4}; and addedArray = {1,4,5};
I want an efficient way to get these two arrays - removedArray and addedArray from the old and new NSMutableArray. Thanks! If the problem is not very understandable, I'm willing to provide more information.
Edit 1
Perhaps it will be more clear if I explain what I want to use this for.
Actually what I am using this for is updating a UITableView with methods insertRowsAtIndexPaths and removeRowsAtIndexPaths with animation after the tableview gets loaded, so that the user can see the removed rows go out and the new rows come in. The tableview stores the Favourites elements which the user can add or remove. So after adding some favorites and removing some; when the user comes back to the favourites tableview, the animations will be shown.
Edit 2
Should have mentioned this earlier, but the elements in both the old and the new array will be in an ascending order. Only the indices of the removal or addition matters. The order cannot be changed. ex. {#"b",#"a",#"c",#"d"} cannot be an array.
I have tried iterating through the old and the new arrays using loops and if conditions, but is it getting really messy and buggy.
This is not a simple problem. First, note that it may have multiple solutions:
a b c d
b c d e
both (a={0, 1, 2, 3}, r={0, 1, 2, 3}) and (a={3}, r={0}) are valid solutions. What you are probably looking for is a minimal solution.
One way to get a minimal solution is by finding the Longest Common Subsequence (LCS) of the two sequences. The algorithm for finding LCS will tell you which elements of the two sequences belong to the LCS, and which do not. Indexes of each element of the original array that is not in LCS go into the removed array; indexes of elements of the new array that are not in LCS go into the added array.
Here are a few examples (I parenthesized the elements of LCS):
0 1 2 3 4 5
(a) b (d) (e) g
(a) c (d) (e) f h
The items of old not in LCS are 1 and 4; the items of new not in LCS are 1, 4, and 5.
Here is another example:
0 1 2 3
a (b) (c) (d)
(b) (c) (d) e
Now added is 3 and removed is 0.
addedArray = newArray ∖ (newArray ∩ oldArray)
= newArray ∖ ({#"a",#"c",#"d",#"e",#"f",#"h"} ∩ {#"a",#"b",#"d",#"e",#"g"})
= newArray ∖ {#"a",#"d",#"e"}
= {#"a",#"c",#"d",#"e",#"f",#"h"} ∖ {#"a",#"d",#"e"}
= {#"c",#"f",#"h"}
removedArray = oldArray ∖ (oldArray ∩ newArray)
= oldArray ∖ ({#"a",#"b",#"d",#"e",#"g"} ∩ {#"a",#"c",#"d",#"e",#"f",#"h"})
= oldArray ∖ {#"a",#"d",#"e"}
= {#"a",#"b",#"d",#"e",#"g"} ∖ {#"a",#"d",#"e"}
= {#"b",#"g"}
To find intersections of array, you can view the following SO post:
Finding Intersection of NSMutableArrays
If both arrays are already sorted in ascending order, you can find the added and removed
elements with a single loop over both arrays (using two independent pointers into the array):
NSArray *oldArray = #[#"a",#"b",#"d",#"e",#"g"];
NSArray *newArray = #[#"a",#"c",#"d",#"e",#"f",#"h"];
NSMutableArray *removedArray = [NSMutableArray array];
NSMutableArray *addedArray = [NSMutableArray array];
NSUInteger iold = 0; // index into oldArray
NSUInteger inew = 0; // index into newArray
while (iold < [oldArray count] && inew < [newArray count]) {
// Compare "current" element of old and new array:
NSComparisonResult c = [oldArray[iold] compare:newArray[inew]];
if (c == NSOrderedAscending) {
// oldArray[iold] has been removed
[removedArray addObject:#(iold)];
iold++;
} else if (c == NSOrderedDescending) {
// newArray[inew] has been added
[addedArray addObject:#(inew)];
inew++;
} else {
// oldArray[iold] == newArray[inew]
iold++, inew++;
}
}
// Process remaining elements of old array:
while (iold < [oldArray count]) {
[removedArray addObject:#(iold)];
iold++;
}
// Process remaining elements of new array:
while (inew < [newArray count]) {
[addedArray addObject:#(inew)];
inew++;
}
NSLog(#"removed: %#", removedArray);
NSLog(#"added: %#", addedArray);
Output:
removed: (
1,
4
)
added: (
1,
4,
5
)

iOS NSMutableString returns weird character

I make an array of several words, then I put all words into a mutable string, and then a mutable array of every character of this string. However, "wordSplitted" that is a mutable array of the characters give random scrambled characters at each startup of app in Simulator, showing in the log:
2012-07-22 09:12:01.108 xxx[4484:b603] wordSplitted contains: (
"",
"",
"\U221e",
"-",
G,
N,
P,
"",
""
)
It should be b, i, l, h, u, k, s, k, j.
NSArray *threeWords = [NSArray arrayWithObjects:#"bil", #"huk", #"skje", nil];
NSMutableString *allTogether = [[NSMutableString alloc]init];
/*
for (NSString *s in threeWords)
{
[allTogether appendString:s];
}
*/
for (int b = 0; b < [threeWords count]; b++)
{
[allTogether appendString:[threeWords objectAtIndex:b]];
}
NSLog (#"allTogether contains %#", allTogether);
//[threeWords release];
[allTogether release];
NSMutableArray *wordSplitted = [[NSMutableArray alloc]init];
//this function gives me headache
for (int a = 0; a < 9; a ++)
{
//gives also scrambled characters
//[wordSplitted addObject:[NSString stringWithFormat:#"%C",[allTogether characterAtIndex:a]]];
NSRange range = {a,1};
[wordSplitted addObject:[allTogether substringWithRange:range]];
}
NSLog (#"wordSplitted contains: %#", wordSplitted);
How can I display normal characters like alphabets?
You call [allTogether release] but then reference it later on. Normally this would cause your program to crash, but something about the CFMutableArray backing makes this not always happen.
Basically, don't release the array until you're sure you're done using it.
about string splitting
http://www.idev101.com/code/Objective-C/Strings/split.html

Resources