NSDictionary and comparing SetObjects - objective-c

Hi I'm wondering how to compare the contents of the setObjects stored with keys in an NSDictionary: Here's my code I'm working with:
[INNumbers setObject:#"0,1,2,3,4,5,6,7" forKey:#"0"];
[INNumbers setObject:#"4,5,6,7,8,9,10,11" forKey:#"1"];
I'm wonder how I would compare the 2 keys and find if there are similar numbers like if 7 occurs in both?
//this will get the numbers in the keys for me
id number1 = [INNumbers objectForKey:#"0"];
id number2 = [INNumbers objectForKey:#"1"];
but I'm not sure how to compare what number1 and number2 retrieve.

If I was not force to use strings, I would do it this way:
NSArray *nums0 = #[#1,#2,#3];
NSArray *nums1 = #[#3,#4,#5];
NSMutableSet *intersection = [NSMutableSet setWithArray:nums0];
[intersection intersectSet:[NSSet setWithArray:nums1]];
NSArray *numsInCommon = [intersection allObjects];
numsInCommon will contain #3 that is the number that is in both arrays

In your example, the values stored in the dictionary are string literals, which are hard to parse and test for membership tests repeatedly. Perhaps you wanted to use NSSets:
#import <Foundation/Foundation.h>
int main()
{
NSSet *numbers1 = [NSSet setWithObjects:#0, #1, #2, nil];
NSSet *numbers2 = [NSSet setWithObjects:#0, #4, #5, nil];
if([numbers1 intersectsSet : numbers2]) {
NSLog(#"The two sets have at least one element in common!");
/* Let's obtain the intersection: */
NSSet *common = [numbers1 objectsPassingTest:^BOOL(id obj, BOOL *stop) {
if ([numbers2 containsObject:obj]) {
return YES;
} else {
return NO;
}
}];
for (id o in common) {
NSLog(#"%#", o);
}
}
return 0;
}

Related

Return all sets where all of its numbers are not in any other set

I recently had to solve the following algorithm question, which it confused me.
Suppose you have an array of sets that contain integers. Write a
function that returns all sets where all of its numbers are not in any
other set.
EXAMPLE {0,4,9}, {3,4,5}, {6,7,8}
RESULT {6,7,8}
The code should be in Objective-C or Swift.
[EDIT]
I came up so far with something like that but can't really finish it.
- (NSArray*) getDisjointedSets:(NSArray*)sets {
NSArray* resultedSet;
NSMutableArray* indexDoesntExistInSets = [NSMutableArray array];
[sets enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSArray* nextIndexArray = [sets objectAtIndex:idx+1];
NSNumber* numberIndex = obj;
[nextIndexArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSNumber* numberNextIndex = obj;
if (numberIndex.intValue == numberNextIndex.intValue) {
// number exists in the next set, continue
*stop = YES;;
} else {
[indexDoesntExistInSets addObject:numberIndex];
}
}];
}];
return resultedSet;
}
Your code iterates the array of arrays. But then you get the next array, iterate its numbers but try to compare each of those numbers against the current set.
Assuming you have an NSArray of NSArray objects, you can do this:
- (NSArray *)getDisjointedSets:(NSArray *)sets {
NSMutableArray *resultSet = [NSMutableArray array];
for (NSArray *arrayA in sets) {
BOOL noMatch = YES;
for (NSArray *arrayB in sets) {
// Skip if both are the same array
if (arrayA != arrayB) {
NSMutableSet *setA = [NSMutableSet setWithArray:arrayA];
NSSet *setB = [NSSet setWithArray:arrayB];
[setA intersectSet:setB];
if (setA.count) {
// The two sets have something in common
noMatch = NO;
break;
}
}
}
if (noMatch) {
[resultSet addObject:arrayA];
}
}
return resultSet;
}
Test code:
NSArray *sets = #[
#[ #0, #4, #9 ],
#[ #3, #4, #5 ],
#[ #6, #7, #8 ]
];
NSArray *result = [self getDisjointedSets:sets];
NSLog(#"results = %#", result);

Compare two arrays with the same value but with a different order

I have 2 nsarray, with the same values but in different order.
NSArray * array1 = {0,1,2,3}
NSArray * array2 = {2,3,1,0}
I need a method to determinate if two arrays have the same values in a different order.
Kind of
-(BOOL) isSameValues:(NSArray*)array1 and:(NSArray*)array2;
You can use NSCountedSet for that purpose:
- (BOOL)isSameValues:(NSArray*)array1 and:(NSArray*)array2
{
NSCountedSet *set1 = [NSCountedSet setWithArray:array1];
NSCountedSet *set2 = [NSCountedSet setWithArray:array2];
return [set1 isEqualToSet:set2];
}
NSCountedSet is a collection of different objects, where each object has an associated counter with it. Therefore the result for
NSArray *array1 = #[#0,#1,#2,#3];
NSArray *array2 = #[#2,#3,#1,#0];
is YES, but for
NSArray *array1 = #[#1,#1,#3,#3];
NSArray *array2 = #[#3,#3,#3,#1];
the result is NO.
Update: this will not work if arrays have duplicate elements!
You could create two NSSets with those arrays and the compare them.
NSArray * array1 = #[#0,#1,#2,#3];
NSArray * array2 = #[#2,#3,#1,#0];
NSSet *set1 = [NSSet setWithArray:array1];
NSSet *set2 = [NSSet setWithArray:array2];
NSLog(#"result %#", [set1 isEqualToSet:set2] ? #"YES" : #"NO");
if ([[NSSet setWithArray:array1] isEqualToSet:[NSSet setWithArray:array2]]) {
// the objects are the same
}
Take total no of elements. Have a counter. And put double 'for loop' to parse through each and every element of each other. Increment the counter at each matching.
Note : This is valid when all elements are unique.
If different or you don't know, sort them and match one to one.
An other way would be to use a NSHashTable.
- (BOOL)array:(NSArray *)array1 containsTheSameObjectsAsArray:(NSArray *)array2 {
if (array1.count != array2.count) {
return NO;
}
NSHashTable *table = [[NSHashTable alloc] initWithOptions:NSHashTableWeakMemory
capacity:array1.count];
for (NSObject *object in array1) {
[table addObject:object];
}
for (NSObject *object in array2) {
if (![table containsObject:object]) {
return NO;
}
}
return YES;
}
Note that NSHashTable requires iOS 6+

find element inside array of dictionaries for a given value

I have two NSArray variables, each one of then gets a similar NSDictionary inside.
For a given row (indexPath.row):
NSArray* array1 = ...;
NSDictionary* item = [array1 objectAtIndex:indexPath.row];
int myid = [[item valueForKey:#"id"] intValue];
// id = 5
Now I need to find the element with id = 5 in array2, but because I'm a c# developer, I think it is a little weird to use a for to do that.
Is there any alternatives to a for?
NSArray has a method indexOfObjectPassingTest which you can use:
NSArray *array2 = ...;
int searchId = ...;
NSUInteger index2 = [array2 indexOfObjectPassingTest:^BOOL(NSDictionary *item, NSUInteger idx, BOOL *stop) {
BOOL found = [[item objectForKey:#"id"] intValue] == searchId;
return found;
}];
if (index2 != NSNotFound) {
// First matching item at index2.
} else {
// No matching item found.
}
This returns the first matching index. If you need all matching indexes, use indexesOfObjectsPassingTest.

How do I compare if *ALL* strings of a NSArray are equal ?

How do I compare if all strings of a NSArray are equal ?
Should I scan the array for each string ?
thanks
You could do this by creating a new set from the array. The set will only contain unique entries so if the number of elements in the set is 1 then all items in the array was equal.
NSSet *uniqueItems = [NSSet setWithArray:yourArray];
if ([uniqueItems count] < 2) {
// All items in "yourArray" are the same (no matter how many they are)
}
In the above example I'm considering an empty set (meaning an empty array) as a being unique as well. If you don't then you can change the if-statement to if ([uniqueItems count] == 1) { ... }
This will also work for any object, not just strings.
The NSArray class is general-purpose so it won't contain functionality to perform this, so yes, you'll have to check each string yourself.
trojanfoe is right. You can enhance NSArray with category and do something like this ...
NSArray *array = #[ #"A", #"B", #"C" ];
__block BOOL allObjectsAreEqual = YES;
if ( array.count > 1 ) {
NSString *firstObject = array[0];
[array enumerateObjectsUsingBlock:^void(id obj, NSUInteger idx, BOOL *stop) {
if ( idx == 0 ) {
return;
}
if ( ( allObjectsAreEqual = [firstObject isEqualToString:obj] ) == NO ) {
*stop = YES;
}
}];
// And here check for allObjectsAreEqual ...
... there're many ways how to do this.
Are you wanting to check whether all the strings are equal to each other?
#interface NSArray (MyAdditions)
- (BOOL) isFilledWithEqualObjects {
if (!self.count) return YES;
id firstObject = [self objectAtIndex:0];
for (id obj in self) {
// Avoid comparing firstObject to itself (and any other pointers to
// firstObject)
if (firstObject == obj) continue;
if (![firstObject isEqual:obj]) return NO;
}
return YES;
}
#end
That example uses -isEqual:, to work with any kind of object. If you know the contents are strings, you can use -isEqualToString: instead:
if (![firstObject isEqualToString:obj]) return NO;

Get matched string from two NSArrays

How can I save the string that match from one NSArray with one index difference in NSMutableArray?
For example, there are three "apple", four "pineapple", six "banana", two "cocoa" and the rest of words dont have duplicate(s) in the nsarray, i would like to know if the nsarray has at least two same words. If yes, I would like to save "apple", "pineapple, "banana" and "cocoa" once in nsmutablearray. If there are other alike words, I would like to add them to namutablearray too.
My code (which still doesn't work properly);
NSArray *noWords = [[NSArray alloc] initWithArray:
[[NSString stringWithContentsOfFile:[[NSBundle mainBundle]
pathForResource:#"words" ofType:#"txt"]
encoding:NSUTF8StringEncoding error:NULL]
componentsSeparatedByString:#"\n"]];
NSUInteger scount = [noWords count];
int ii = 0;
NSString *stringline;
for (ii; ii < scount; ii++)
{
stringline = [noWords objectAtIndex:ii];
NSLog(#"stringline : %# ", stringline);
}
int i = 1;
NSString *line;
for (i ; i < 10; i++)
{
line = [noWords objectAtIndex:i];
NSLog (#"line : %# ", line);
NSMutableArray *douwords = [NSMutableArray array];
if ([stringline isEqualToString:line])
{
NSString *newword;
for (newword in douwords)
{
[douwords addObject:newword];
NSLog (#"detected! %# ", douwords);
}
}
}
Here's a solution using two sets:
- (NSArray *)getDuplicates:(NSArray *)words
{
NSMutableSet *dups = [NSMutableSet set],
*seen = [NSMutableSet set];
for (NSString *word in words) {
if ([seen containsObject:word]) {
[dups addObject:word];
}
[seen addObject:word];
}
return [dups allObjects];
}
Assuming NSSet uses hash tables behind the scenes (which I'm betting it does), this is going to be faster than the previously suggested O(n^2) solution.
Here's something off the top of my head:
NSMutableSet* duplicates = [NSMutableSet set];
NSArray* words = [NSArray arrayWithObjects:#"Apple", #"Apple", #"Orange", #"Apple", #"Orange", #"Pear", nil];
[words enumerateObjectsUsingBlock:^(NSString* str, NSUInteger idx, BOOL *stop) {
for (int i = idx + 1; i < words.count; i++) {
if ([str isEqualToString:[words objectAtIndex:i]]) {
[duplicates addObject:str];
break;
}
}
}];
NSLog(#"Dups: %#", [duplicates allObjects]); // Prints "Apple" and "Orange"
The use of an NSSet, as opposed to an NSArray, ensures strings are not added more than once. Obviously, there are optimizations that could be done, but it should be a good starting point.
I assume that you want to count appearances of words in your array and output those with a count of more than one. A basic and verbose way to do that would be:
// Make an array of words - some duplicates
NSArray *wordList = [[NSArray alloc] initWithObjects:
#"Apple", #"Banana", #"Pencil",
#"Steve Jobs", #"Kandahar",
#"Apple", #"Banana", #"Apple",
#"Pear", #"Pear", nil];
// Make an mutable dictionary - the key will be a word from the list
// and the value will be a number representing the number of times the
// word appears in the original array. It starts off empty.
NSMutableDictionary *wordCount = [[NSMutableDictionary alloc] init];
// In turn, take each word in the word list...
for (NSString *s in wordList) {
int count = 1;
// If the word is already in the dictionary
if([wordCount objectForKey:s]) {
// Increse the count by one
count = [[wordCount objectForKey:s] intValue] + 1;
}
// Save the word count in the dictionary
[wordCount setObject:[NSNumber numberWithInt:count] forKey:s];
}
// For each word...
for (NSString *s in [wordCount keysOfEntriesPassingTest:
^(id key, id obj, BOOL *stop) {
if ([obj intValue] > 1) return YES; else return NO;
}]) {
// print the word and the final count
NSLog(#"%2d %#", [[wordCount objectForKey:s] intValue], s);
}
The output would be:
3 Apple
2 Pear
2 Banana