I have an 3 NSMutableArray objects that contain CMTime objects. How can I iterate through all three of them in an efficient manner and find out if there are duplicate values in all three? For example, I'm iterating through one of time and reading the value and storing it in x. Now, I want to see if x occurs (at any position) within the other two arrays. I tried looking for a contains method, but couldn't find one. I did come across filterUsingPredicate, but I'm not sure if this is the best way of doing it nor how to actually use predicates.
I tried looking for a contains method, but couldn't find one.
Use indexOfObject:
like this:
if ([array indexOfObject:object] != NSNotFound) {
// object found
}
else {
// object not found
}
You can use ([yourArray indexOfObject:x] != NSNotFound) in place of your missing contains method. However, if you're doing this quickly, often, or with a lot of elements, you should consider using NSMutableOrderedSet, which is ordered like NSMutableArray, but offers a quick and efficient contains method, as well as allowing quick operations like union and intersection, which might allow you to redesign your algorithm to iterate through your elements much less.
Related
I'm currently trying to teach myself Objective-C and was playing around with an exercise where I needed to sort an array.
I managed to complete it using the following code:
NSSortDescriptor * newSortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"title" ascending:TRUE];
NSArray *sortDescriptors = [NSArray arrayWithObject:newSortDescriptor];
[self.theBookStore sortUsingDescriptors:sortDescriptors];
My question is about what is actually happening here. I don't really understand exactly what I've done.
Line 1: I understand here I've created a new object that has a descriptor. This has two parameters, the column I want to sort on and that it is ascending.
Line 2: This is the line I'm confused about. Why do I need an array of sort descriptors? When I read this code I suspect it creates an array with only one row is that correct?
Line 3: I understand that this is calling the sortUsingDescriptors method but again, my confusion is why this function expects an array.
I've read the documentation but I'm really looking for a simple explanation.
Any help is much appreciated
Line 1: I understand here I've created a new object that has a
descriptor. This has two parameters, the column I want to sort on and
that it is ascending.
Really, you've created an object that is a descriptor. It describes how to sort the array.
Line 2: This is the line I'm confused about. Why do I need an array of
sort descriptors? When I read this code I suspect it creates an array
with only one row is that correct?
Right -- you've created an array that contains a single object. You could create an array that has ten or fifteen or eighty-seven sort descriptors, if you really wanted to sort on that many fields. More often, you use one, two, maybe three. So, if you're sorting a list of people, you might add sort descriptors that specify last name and first name. That way, people that have the same last name will be arranged within that group according to their first name.
Line 3: I understand that this is calling the sortUsingDescriptors
method but again, my confusion is why this function expects an array.
Again, it's so that you can have primary, secondary, tertiary (etc.) sort keys. You could have a separate method that takes a single sort descriptor instead of an array for those times when you want to sort on only one key. NSArray doesn't provide that, but you can always add it in a category if you want:
#category NSArray (SingleSortDescriptor)
- (NSArray*)sortUsingDescriptor:(NSSortDescriptor*)descriptor;
#end
#implementation NSArray (SingleSortDescriptor)
- (NSArray*)sortUsingDescriptor:(NSSortDescriptor*)descriptor
{
return [self sortUsingDescriptors:[NSArray arrayWithObject:descriptor]];
}
#end
Line 1: .. yes your right. You are creating a custom object called NSSortDescriptor. That object defines a attribute to sort after. You did enter "title". So the objects in your array-to-sort will be sorted after that property (yourObject.title "kind-of").
Line 2: Because the sorting method (sortUsingDescriptors) always needs a array, you need to create a NSArray with only one object. Okay, ... looks kind of stupid. But makes absolute sense. Lets say you would like to sort after two criteria (lets say "title", then "city").
Line 3: Yes heres must be a array because of sorting after more then one criteria.
And always keep the memory clean:
On line 1 you did allocate/init a NSSortDescriptor.
So clean up after using it (if you are not using ARC).
So add a line:
[newSortDescriptor release];
Multiple sort descriptors would be used to resolve what happens if there are multiple matches. I's a priority order. A second descriptor would tell it what to do if it found two titles the same.
I have a mutable array that contains the sounds that are being played.
I have a continous process that parse that array to adjust volumes and some other things.
Sometimes, a new sound is played and must be added to that array just before it's play starts.
And sometimes, I have a crash because my array "was mutated while being enumerated".
How may I solve that ?
You can't easily change an array while it's enumerating.
Enumerate through the array and note the new sound to be added (using a variable, or a separate array if you need to note more than one). When the enumeration is finished, add the sound to the array.
Alternatively, make a copy of the array, enumerate the copy and add the sound to the original one when you need to.
It would be nice to see any code here. But according what you are saying, i think the problem lies in the way that you use to iterate through the array. I guess it looks like this:
for ( type *object in myArray) {
...
}
Now, as you exception tells you, you can't modify the array while doing this. If you, on the other hand, access the array's values via the indexes, it should work:
for (int i = 0; i < myArray.count; i++) {
[myArray objectAtIndex:i]...
}
Keep in mind however, that the indexes aren't 'stable' that way, especially if you remove objects.
I want to create meachanical units convertor calculator in iphone sdk so i have to perform one to many type of operation. for example Length is category and there is multiple type of units in Length category for ex.meter,kilometer etc.Now for every unit i will have to create multiple combinations for that i'm using if-else conditions for now to work but practially this increases my code a lot because as there are almost 30 categories and each category has multiple units.So is there any another way to solve this problem in short way as it is too hectic to write so many if else combinations in my code. For this i thought that it might be possible to use two dimensional array.so please provide me code for two dimensional array to perform this calulation operation.
Just put NSArray objects in an NSArray and you have your 2 dimenensional array. (pretty much like in any other language.)
NSMutableArray * myTwoDimensionalArray = [NSMutableArray alloc]init];
[myTwoDimensionalArray addObject:[NSArray arrayWithObjects:#"value 0/0", #"value 0/1",nil]];
[myTwoDimensionalArray addObject:[NSArray arrayWithObjects:#"value 1/0", #"value 1/1",nil]];
// to get value at [i][j]
[[myTwoDimensionalArray objectAtIndex:i] objectAtIndex:j];
As jules has suggested you can use a NSMutableArray yo create your 2-d array. Another approach would be to have mXn number of objects in a single NSMUtableArray. Create a array and add objects sequentially. Access the [i][j] element by accessing the object at (i*n)+j.
I want to add items to mutable array from a dictionary. Problem is I want to check existing array items before adding new item. If same item is already there in the array, I want to replace it. else add the new item.
How could I do it?
You could perhaps use an NSMutableSet rather than an NSMutableArray. The addObject method on NSMutableSet will only "add a given object to the set, if it is not already a member."
If you'd like to check membership before adding to the set anyway, you can check the result of:
[mySet containsObject:myObjectFromDictionary]
...which returns a simple BOOL value indicating whether the set already contains an object whose isEqual method returns true when your object is passed to it.
(For a little extra functionality, NSCountedSet will keep track of the number of objects added to the "set" for which isEqual: returns true)
You could compare the result of : [yourArray indexOfObject:yourObject]; against NSNotFound to know if the object is in the array.
It will give you the index of the object to replace, or if it is equal to NSNotFound, you will add it.
Objects equality is tested with isEqual: method.
NSArray class reference.
On the face of it, both Vincent's and Rich's answers are correct.
However, there is a conceptual issue in the original question that hasn't been addressed.
Namely, that "membership in an array" via indexOfObject: (or containsObject: in a set) is ultimately done by comparing the two objects using isEqual:.
If isEqual: returns YES, then the two objects better had damned well be functionally identical in your code or else you have other, significantly more serious, problems in your design and implementation.
Thus, the real question should be "How do I detect if an object is already in an array and not add it?" and Rich's and Vincent's answer are both still correct.
I.e. you should only need to check for presence and, if present, take no action.
(Note that there are esoteric situations where replacement is actually warranted, but they are both truly esoteric and not generally used within the context of a mutable collection)
I just want to know if an object is in an array or not.
So I can use:
- (BOOL)containsObject:(id)anObj
But it would send -isEqual to every object in the array. Bad when there are thousands of them.
And then there is:
- (NSUInteger)indexOfObjectIdenticalTo:(id)anObject
which seems to only compare the memory addresses. I think this is faster. But a bit nasty to use, of course. One would have to check for NSNotFound.
Is -indexOfObjectIdenticalTo really the best option?
if you really need this often, you can create an instance method by category:
#interface NSArray (MONStuff)
- (BOOL)mon_containsObject:(id)object;
#end
#implementation NSArray (MONStuff)
- (BOOL)mon_containsObject:(id)object {
return NSNotFound != [self indexOfObjectIdenticalTo:arg];
}
#end
or these's also CFArrayContainsValue.
a simple function would also suffice.
But a bit nasty to use
Why? It seems to me that
if ([array indexOfObjectIdenticalTo: foo] != NSNotFound)
{
// do what you need
}
is not much more nasty than
if ([array containsObject: foo])
{
// do what you need
}
Which one you choose depends on what equality semantics you use. You almost certainly want to use -containsObject: for arrays containing NSStrings or NSNumbers because -isEqual: gives the correct equality semantics.
Both methods, by the way are O(n) which is where the real performance problem is. If the idea of a linear search is a problem, consider a different data structure e.g. based on NSDictionary.
As per your explaining and comparison indexOfObjectIdenticalTo seems me the first choice to use..
Here is one more SO post ..
indexOfObject vs. indexOfObjectIdenticalTo
If possible (for example if sorting order is irrelevant) you could use an NSDictionary instead, with your object as keys and values of [NSNull null]. Note that the objects get copied when used as keys ! Your objects would need to implement the - (NSUInteger)hash method.
Also see the excellent NSArray or NSSet, NSDictionary or NSMapTable analysis from Matt Gallagher.