quick question. I have two NSMutableArray:
Array 1: [A,B,C,D,E,F];
Array 2: [B,E,F];
Note that Array 2 is always subset of Array 1 - meaning objects that exist is Array 2, definitely exist is Array 1 as well.
So what I want is to build an array that contain the objects that are NOT in Array 2. Like so
Array 3: [A,C,D];
I've tried using relative complement as outlined in this post but the resulting array is basically the same as Array 1. It doesn't eliminate the objects that exist in Array 2.
I also tried the answer here as well, but still not getting what I want. Unless i'm really doing something very obviously wrong.
Using NSPredicate is much preferable, I guess. But I'm open to ideas and hints.
Note: Just for context, i'm doing this to update my UITableView, basically for data filtering purposes.
Thanks!
UPDATE
So all the answers given so far actually works with simple set of dummy data for me. But when I tested with my real data, the Array 3 that are created is still the same as the Array 1. So, I'm going to give more info about my stuff.
Both arrays are NSMutablArray that store dictionary objects. I'm actually using Parse.com, so the objects in both arrays are PFObject (which is just NSObject, if I'm not mistaken). I don't know how does this affect anything, but yeah, seems to not be working.
Here is a screenshot from the console when I try to step through the process.
Thanks for the help so far guys.
There's no need to go down the predicate route here, you know explicitly what you want to do, and can be expressed with simple, native APIs.
NSMutableArray *mArray3 = [NSMutableArray arrayWithArray:array1];
[mArray3 removeObjectsInArray:array2];
NSArray* array3 = [mArray3 copy];
An important thing to note:
removeObjectsInArray:
This method assumes that all elements in otherArray respond to hash and isEqual:.
For an object to be deemed equal, they need to response to hash and isEqual:, and for those values to match between two equal objects. A good article regarding equality can be read here.
If PFObject simply inherits from NSObject, then the equality checking will be very basic. It will simply check for equality by asking "Are these objects the same object, based on location in memory?". This probably explains why your dummy data works, but the real data does not.
You'll need to subclass PFObject to make it aware of the contents. This means you can override hash and isEqual: to provide a more reasonable statement of equality. For example, "Are these objects the same object, based on the value of the 'name' property". It's up to you to define what makes objects equal.
WDUK's answer is probably the way to go since it's simpler and requires only one new object (plus a copy of that). However, if you like discrete math, NSMutableSet allows you to perform set operations. That is, another (overly complicated, however, very descriptive) answer to your question is:
// convert arrays to sets.
// since array2 is always a subset of array1, we don't need to create a union set.
NSMutableSet *set1 = [NSMutableSet setWithArray:array1];
NSSet *set2 = [NSSet setWithArray:array2];
// find intersecting objects
NSMutableSet *intersection = [NSMutableSet setWithSet:set1];
[intersection intersectSet:set2];
// remove intersecting objects (result: your desired set)
[set1 minusSet:intersection];
NSArray *nonIntersectingObjects = [set1 allObjects];
As WDUK suggests, your problem is easily solved with an NSMutableArray. However, when similar, but more complex, problems arise, set operations might provide an simpler and more elegant solution.
If you want to do it using a predicate here's the way to do it:
NSArray* array1= #[#'A',#'B',#'C',#'D',#'E',#'F'];
NSArray* array2= #[#'B',#'E',#'F'];
NSPredicate* predicate= [NSPredicate predicateWithFormat: #"not(self in %#)",array2];
NSArray* array3=[array1 filteredArrayUsingPredicate: predicate];
SELF represents the evaluated object in the array. The IN operator can be used to check if any object is inside a collection, here is some reference: Predicate programming guide / aggregate operations
Related
Say I want to access all objects in some NSDictionary object.
I want to iterate like this:
for (key in dict){}
Is it guaranteed that for each run the objects in the dictionary will be accessed in the same order?
PS. Let me explain my question more thoroughly: if I iterate dictionary once and access keys in some concrete order - will I have the same order on second iteration attempt?
Sorting of keys is not guaranteed because of the nature a key is placed inside the NSDictionary. But that is only the half answer. read on...
If we iterate thru the dict with a for (NSString* key in dict) loop or even more unspecific with for (id<NSCopying> key in dict) loop then we use actually NSEnumeration. Those kind of iterations are unpredictable to you. NSEnumeration and NSFastEnumeration do not iterate the dict with indexes. They go thru by addresses or hashes of keys, so to speak. Thats also a blurry answer that is not complete.
Keys inside a dict are unique compared to other keys in the same dict.
Which is the great thing and why you would use a NSDictionary or NSMutableDictionary instead of indexed NSArray or NSPointerArray or unspecific NSSet, and specially offered datatypes as NSOrderedSet, NSOrderedCollection. NSMapTable and NSHashTable tend to behave like NSDictionaries but they have a completely different way how they store the keys and how they iterate.
So what happens when you rewrite a keyed value in NSDictionary?
NSDictionary *dict = #{
#"A" : #(1234),
#"B" : #(4321)
}
NSMutableDictionary *mutabledict = [dict mutablecopy];
mutabledict[#"A"] = #(5678); //beware this only works on NSMutableDictionary.
dict = mutabledict;
here we exchange the value of the first declared key A.
mutabledict[#"A"] [key] is a getter subscript used to find the address of the keys value pair. Nothing is changed on the key itself. So the order of keys stays as it was the moment the unique key was copied in.
You need to be careful when you create a mutablecopy, because then whole pairs are copied. The outcome in sorting may be unpredictable as well.
Simple: But Accessing keys value does not change their memory layout.
But: NSDictionary are immutable, so the keys can not be changed once they are set. So you can say:
The keys are ordered in the order they where stored the first time. But you can't access the values stored in a guaranteed order when you don't know the order the keys:value pairs where placed and with this process its unique keys copied into the dict.
If you can't control the order the keys are set then the keys order is unknown to you, (respecting the question) not undefined. And NSEnumeration iteration gives you not a real picture of the order they are stored.
How to deal with that?
The easies way to get known ordered sorting of keys is by manually sorting all its keys like..
NSArray *sortedKeys = [dict.allKeys sortedArrayUsingSelector:#selector(compare:)];
which is giving you ascending order of keys and lets you iterate thru your dict with arrays indexes containing addresses to keys. like ..
for (unsigned int i=0; i<sortedKeys.count; i++) {
NSString* key = sortedKeys[i];
dict[ key ] = yourValue;
}
if keys are not of interest but the guaranteed sorting is more important to you, then you could convert the NSDictionary into a sorted NSArray without keys and access its indexes in a loop. With the obvious back-draw to have no keys unless you store them manually.
id notfoundmarker = #"empty";
NSArray *sortedkeys= [dict.allKeys sortedArrayUsingSelector:#selector(compare:)];
NSArray *oneForOneSorted = [dict objectsForKeys:sortedkeys notFoundMarker:notfoundmarker];
for (unsigned int i=0; i<oneForOneSorted.count; i++) {
id<NSObject> value = oneForOneSorted[i];
NSLog(#"%#", value);
};
My question was different: if I iterate dictionary once and access keys in some concrete order - will I have the same order on second iteration attempt?
Short Answer
In all probability yes
Longer Answer
How a dictionary is constructed internally is not specified, and there are multiple ways to represent dictionaries, all that is known is that key values must be hashable which implies hashing is used somehow.
It is also not know what algorithm a dictionary uses to provide the keys when enumerating them, and again for an particular possible representation there could be more than one enumeration algorithm possible.
So we have a lot of unknowns.
What do we know?
In the absence of threading, random number generation, and anything similar an Objective-C program is deterministic, a trait it has in common with C, Swift, Java, C# and a host of other languages.
NSDictionary is not thread-safe so its unlikely to use threading in its implementation.
And why would it use random numbers?
NSDictionary is also an immutable type so once constructed there is no obvious reason to re-order its internal storage in response to calls querying its contents.
So, in all probability, you will get the same key order on every enumeration.
Without the source though you can't be certain, you cannot prove the absence of something by black-box testing. Maybe the programmer decided that every millionth enumeration they'd throw a little randomness in – just for fun ;-) Is this likely? Maybe not (its probably a good way to get fired!), but it's not impossible.
If you ask out of curiosity, then good stay curious!
If however you want to rely on the order being deterministic for code correctness then sort the keys (into a peculiar order if you wish as long as its deterministic), the cost of doing so will in all probability be inconsequential.
HTH
The docs state that for the allKeys property the order of the elements in the array is not defined.
So you can just sort the keys array to ensure it's always sorted.
Each iteration will be in a random order because Swift dictionaries don't prioritize order. Arrays do, however, so you can sort the dictionary (by key or value) to produce an array of tuples, which in effect can be treated like a sorted dictionary.
let dictionary = ["k4": 3, "k2": 8, "k1": 6]
let sortedArrayOfTuples = dictionary.sorted(by: { $0.key < $1.key })
for entry in dictionary {
print(entry.key)
}
for entry in sortedArrayOfTuples {
print(entry.key)
}
Hiho,
I have a question about querying a realm database. I have realm-objects which contains features in a RLMArray. I want to find all objects which contains all features from a given array.
And in another case I want to find all object which have one of the features.
I try things like this (also with IN):
NSArray *featureArray = #[#"feature1", #"feature2"];
RLMResults* containedObjects = [MyObject objectsWhere:#"features CONTAINS %#", featureArray];
But get errors like: RLMArray predicates must use aggregate operations
I think the problem is, that realm have to check an array with an array for matching. In SQL I think a JOIN-Operation would be a good (not very efficent) way, but I can't found an equivalent operation in NSPredicate.
Thank you for every hint!
As you can't store arrays of values in Realm, I guess that MyObject would have in that case a to-many relation / list property to a class Feature, which might be identified by their name.
CONTAINS is with NSPredicate not what you're looking for here. This is a string comparison operator.
You can use the IN operator, as seen below:
NSArray *featureArray = #[#"feature1", #"feature2"];
RLMResults* containedObjects = [MyObject objectsWhere:#"features.name IN %#", featureArray];
Note: you don't have to worry about performance, as links are first-class citizen in Realm, there are no expensive JOIN operations involved here.
I have an array (NSArray or NSMutableArray doesn't matter): SpecID of specific files IDs (109234, etc.). And I have a large array of all files IDs : FilesID.
I need to check whether FilesID contains all the elements of SpecID.
So the question what is the fastest and most efficient way of doing this except simple comparing all the elements to each other in a loop. May be there are some standard method or efficient algorithm?
You could use sets:
NSSet *specIDs = [NSSet setWithArray:specIDarray];
NSSet *fileIDs = [NSSet setWithArray:fileIDarray];
if ([specIDs isSubsetOfSet:fileIDs])
{
// Your file IDs contains every ID found in specIDarray
}
For this to work efficiently, the objects should ideally be NSNumber objects, or if they are custom objects, they should override both hash and isEqual:. The efficiency of sets depends mostly on having a good hash. The Foundation classes, e.g. NSNumber, NSString etc have good hashes.
Also, if you can, load your IDs directly into sets rather than converting them from arrays as this will be slightly more efficient, but otherwise the above is probably as simple as it would get. There may be specialised algorithms which would perform better but only explore those options if the above is too slow.
Now, I've looked up on this on here and google, and it seems everyone uses NSSet to remove dupes. This is cool and all, but it seems that this method removes the sorting as well.
Is there
1) A way to sort NSSet alphabetically?
2) A better way to remove dupes in NSMutableArray in or outside the for loop where I add them to the array by reading them from a .csv file.
Thanks:)
I believe you want to be using an NSOrderedSet. Here's the documentation on it:
http://developer.apple.com/library/mac/#documentation/Foundation/Reference/NSOrderedSet_Class/Reference/Reference.html
You can construct an NSOrderedSet* from your array; using +orderedSetWithArray: will preserve the array's existing order. If it's not already in the correct order, you can't sort the set directly, so there's little point in using an ordered set, but you can easily construct a regular NSSet and sort that into another array, using -sortedArrayUsingDescriptor:, or even better allObjects, followed by any of NSArray's sorting methods.
On the other hand (it's possible I'll get some nasty comments about this, but...), since NSArray and NSSet seem to be built on top of the same hash table functionality, you could just do this:
id newObj = // Acquire new object from wherever
while( newObj ){
if( ![arrayImConstructing containsObject:newObj] ){
[arrayImConstructing addObject:newObj]
}
newObj = // Acquire next object
}
This is basically what an ordered set has to do when you construct it anyways, and it's quite likely that your array is small enough (if you're putting it into a UIPicker) that you won't notice a performance difference at all. Still, measure the two, and then decide.
*NSOrderedSet is available on iOS > 5.0 (or OS X > 10.7).
NSOrderedSet gives you ordering in a set.
I have used NSSets many times in my apps, but I have never created one myself.
When is it better to use an NSSet as opposed to an NSArray and why?
The image from Apple's Documentation describes it very well:
Array is an ordered (order is maintained when you add) sequence of elements
[array addObject:#1];
[array addObject:#2];
[array addObject:#3];
[array addObject:#4];
[array addObject:#6];
[array addObject:#4];
[array addObject:#1];
[array addObject:#2];
[1, 2, 3, 4, 6, 4, 1, 2]
Set is a distinct (no duplicates), unordered list of elements
[set addObject:#1];
[set addObject:#2];
[set addObject:#3];
[set addObject:#4];
[set addObject:#6];
[set addObject:#4];
[set addObject:#1];
[set addObject:#2];
[1, 2, 6, 4, 3]
When the order of the items in the collection is not important, sets offer better performance for finding items in the collection.
The reason is that a set uses hash values to find items (like a dictionary) while an array has to iterate over its entire contents to find a particular object.
The best answer is to this is Apple's own documentation.
The main difference is that NSArray is for an ordered collection and NSSet is for an unordered collection.
There are several articles out there that talk about the difference in speed between the two, like this one. If you're iterating through an unordered collection, NSSet is great. However, in many cases, you need to do things that only an NSArray can do, so you sacrifice the speed for those abilities.
NSSet
Primarily access items by comparison
Unordered
Does not allow duplicates
NSArray
Can access items by index
Ordered
Allows duplicates
That's all there really is to it! Let me know if that helps.
NSOrderedSet is available in iOS 5+ so with that the main difference becomes whether you want duplicate objects in the data structure.
NSArray:
Ordered collection of data
Allows duplicates
It is collection type object
NSSet:
Unordered collection of data
Does not allow duplicates
It is also collection type object
An array is used to access items by their index. Any item can be inserted into the array multiple times. Arrays mantain the order of their elements.
A set is used basically only to check if the item is in the collection or not. The items have no concept of order or indexing. You cannot have an item in a set twice.
If an array wants to check if it contains an element, it has to check all its items. Sets are designed to use faster algorithms.
You can imagine a set like a dictionary without values.
Note that array and set are not the only data structures. There are other, e.g. Queue, Stack, Heap, Fibonacci's Heap. I would recommend reading a book about algorithms and data structures.
See wikipedia for more information.
NSArray *Arr;
NSSet *Nset;
Arr=[NSArray arrayWithObjects:#"1",#"2",#"3",#"4",#"2",#"1", nil];
Nset=[NSSet setWithObjects:#"1",#"2",#"3",#"3",#"5",#"5", nil];
NSLog(#"%#",Arr);
NSLog(#"%#",Nset);
the array
2015-12-04 11:05:40.935 [598:15730] ( 1, 2, 3, 4, 2, 1 )
the set
2015-12-04 11:05:43.362 [598:15730] { ( 3, 1, 2, 5 )}
The main differences have already been given in other answers.
I'd just like to note that because of the way sets and dictionaries are implemented (i.e. using hashes),one should be careful not to use mutable objects for the keys.
If a key is mutated then the hash will (probably) change too, pointing to a different index/bucket in the hash table. The original value won't be deleted and will actually be taken into account when enumerating or asking the structure for its size/count.
This can lead to some really hard to locate bugs.
Here you can find a pretty thorough comparison of the NSArray and NSSet datastructures.
Short conclusions:
Yes, NSArray is faster than NSSet for simply holding and iterating. As little as 50% faster for constructing and as much as 500% faster for iterating. Lesson: if you only need to iterate contents, don't use an NSSet.
Of course, if you need to test for inclusion, work hard to avoid NSArray. Even if you need both iteration and inclusion testing, you should probably still choose an NSSet. If you need to keep your collection ordered and also test for inclusion, then you should consider keeping two collections (an NSArray and an NSSet), each containing the same objects.
NSDictionary is slower to construct than NSMapTable — since it needs to copy the key data. It makes up for this by being faster to lookup. Of course, the two have different capabilities so most of the time, this determination should be made on other factors.
You would typically use a Set when access speed is of the essence and order doesn’t matter, or is determined by other means (through a predicate or sort descriptor). Core Data for example uses sets when managed objects are accessed via a to-many relationship
Just to add a bit of it i use set sometimes just to remove duplicates from array like :-
NSMutableSet *set=[[NSMutableSet alloc]initWithArray:duplicateValueArray]; // will remove all the duplicate values