I have two array let's say
NSArray *array1=#[ #{#"key1":#"A",#"key2":#"AA"},#{#"key1":#"C",#"key2":#"CC"},#{#"key1":#"E",#"key2":#"EE"},#{#"key1":#"G",#"key2":#"GG"}];
NSArray *array2=#[ #{#"key1":#"A",#"key2":#"AAA"},#{#"key1":#"Z",#"key2":#"ZZZ"}];
I want to subtract the array, This should be the expected reuslt,
NSArray *resultArray=#[ #{#"key1":#"C",#"key2":#"CC"},#{#"key1":#"E",#"key2":#"EE"},#{#"key1":#"G",#"key2":#"GG"}];
I tried the below code but didn't working
NSArray *extracted = [array1 valueForKey:#"key1"];
NSMutableSet *pressieContactsSet = [NSMutableSet setWithArray:extracted];
NSMutableSet *allContactSet = [NSMutableSet setWithArray:array2];
[allContactSet minusSet:pressieContactsSet];
NSLog(#"%#",allContactSet);
Please try below code
First get all key1 objects in temporary array. Then apply filter on array1 and check if your array1 object contain arrayKey1 object.
Make sure it will only check for key1 key.
NSArray *arrKey1 = [array2 valueForKey:#"key1"];
NSPredicate *pred = [NSPredicate predicateWithBlock:
^BOOL(id evaluatedObject, NSDictionary *bindings)
{
if ([arrKey1 containsObject:evaluatedObject[#"key1"]])
{
NSLog(#"found : %#",evaluatedObject);
return NO;
}
else
{
NSLog(#"Not found : %#",evaluatedObject);
return YES;
}
}];
NSArray *arrSubtracted = [array1 filteredArrayUsingPredicate:pred];
NSLog(#"%#", arrSubtracted);
Or you can use enumerateObjectsUsingBlock
NSMutableArray *resultArray = [NSMutableArray new];
[array1 enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop)
{
if (![arrKey1 containsObject:obj[#"key1"]]) {
[resultArray addObject:obj];
}
}];
NSLog(#"%#",resultArray);
Hope this will help you.
This should work.
NSArray *array1=#[ #{#"key1":#"A"},#{#"key1":#"C"},#{#"key1":#"E"},#{#"key1":#"G"}];
NSArray *array2=#[ #{#"key1":#"A"},#{#"key1":#"Z"}];
NSMutableSet *pressieContactsSet = [NSMutableSet setWithArray:array1];
NSSet *allContactSet = [NSSet setWithArray:array2];
[pressieContactsSet minusSet:allContactSet];
NSArray *result = [pressieContactsSet allObjects];
NSLog(#"%#",result);
Enjoy!
NSArray *array1=#[ #{#"key1":#"A"},#{#"key1":#"C"},#{#"key1":#"E"},#{#"key1":#"G"}];
NSArray *array2=#[ #{#"key1":#"A"},#{#"key1":#"Z"}];
NSMutableArray *resultArray = [NSMutableArray arrayWithArray:array1];
[resultArray removeObjectsInArray:array2];
NSLog(#"array %#",resultArray);
Related
I am trying to get common values from two array but insensitive match.But cannot succeed.Whats wrong with the predicate.
NSMutableArray *tempArray1 = [NSMutableArray arrayWithObjects:#"apple", #"cat", nil];
NSMutableArray *tempArray2 = [NSMutableArray arrayWithObjects:#"APPLE", #"CAT", nil];
// NSPredicate *resultPredicate1 = [NSPredicate predicateWithFormat:#"SELF IN [cd] %#", tempArray1];
NSPredicate *resultPredicate1 = [NSPredicate predicateWithFormat:#"SELF [cd] IN %#", tempArray1];
NSMutableArray *arr_filteredtest = [NSMutableArray arrayWithArray:[tempArray2 filteredArrayUsingPredicate:resultPredicate1]];
NSLog(#"%lu",(unsigned long)arr_filteredtest.count);
If you want case insensitive unique set from your two arrays, first you have to either lowercase or uppercase all the strings, and then create NSSet :
NSMutableArray *joindArr = [NSArray arrayWithArray:tempArray1, nil];
[joindArr addObjectsFromArray:tempArray2];
NSMutableArray *arr1 = [[NSMutableArray alloc]init]; //make a nsmutableArray
for (int i = 0; i<[arr count]; i++) {
[arr1 addObject:[[arr objectAtIndex:i]lowercaseString]];
}
NSSet *set = [NSSet setWithArray:(NSArray*)arr1];//this set has unique values
You can achieve intersection using NSSet, unfortunately the search using NSSet is case sensitive.
1.So convert both the arrays to common case, either upperCase or lowerCase
2.Use intersectSet to get result
Example:
NSMutableArray *tempArray1 = [NSMutableArray arrayWithObjects:#"apple", #"cat", nil];
NSMutableArray *tempArray2 = [NSMutableArray arrayWithObjects:#"APPLE", #"CAT", nil];
tempArray2 = [self convertStringObjectsToLoweCase:tempArray2]; //convert all elements to lower case/ upper case
NSSet *set1 = [NSSet setWithArray:tempArray1];
NSSet *set2 = [NSSet setWithArray:tempArray2];
NSMutableSet *mutableSet = [NSMutableSet setWithSet:set1]; //Initialize with parent array,usually array with more elements
[mutableSet intersectSet:set2];
NSArray *arrayContainingCommonObjects = [mutableSet allObjects];
NSLog(#"arrayContainingCommonObjects : %#",arrayContainingCommonObjects);
Use the following helper method
- (NSMutableArray *)convertStringObjectsToLoweCase:(NSMutableArray *)inputArray
{
[inputArray enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
if ([obj isKindOfClass:[NSString class]]) {
NSString *loweCaseString = [(NSString *)obj lowercaseString];
[inputArray replaceObjectAtIndex:idx withObject:loweCaseString];
}
}];
return inputArray;
}
Output:
arrayContainingCommonObjects : (
apple,
cat )
I think you should to try this one
NSMutableArray *tempArray1 = [NSMutableArray arrayWithObjects:#"apple", #"cat", nil];
NSMutableArray *tempArray2 = [NSMutableArray arrayWithObjects:#"apple", #"CAT", nil];
NSMutableSet *intersection = [NSMutableSet setWithArray:tempArray1];
[intersection intersectSet:[NSSet setWithArray:tempArray2]];
NSArray *NEW_ARR = [intersection allObjects];
NSLog(#"new arry:: %#",NEW_ARR);
I have a horizontally and vertically scrollable table. I get the data for the header and first column from the web service(json). I want to sort the data in ascending order and remove duplicate data from both header and the first column. For removing duplicate values I used the following code:
-(void) requestFinished: (ASIHTTPRequest *) request
{
NSString *theJSON = [request responseString];
SBJsonParser *parser = [[SBJsonParser alloc] init];
NSMutableArray *jsonDictionary = [parser objectWithString:theJSON error:nil];
headData = [[NSMutableArray alloc] init];
NSMutableArray *head = [[NSMutableArray alloc] init];
leftTableData = [[NSMutableArray alloc] init];
NSMutableArray *left = [[NSMutableArray alloc] init];
rightTableData = [[NSMutableArray alloc]init];
for (NSMutableArray *dictionary in jsonDictionary)
{
Model *model = [[Model alloc]init];
model.cid = [[dictionary valueForKey:#"cid"]intValue];
model.iid = [[dictionary valueForKey:#"iid"]intValue];
model.yr = [[dictionary valueForKey:#"yr"]intValue];
model.val = [dictionary valueForKey:#"val"];
[mainTableData addObject:model];
[head addObject:[NSString stringWithFormat:#"%ld", model.yr]];
[left addObject:[NSString stringWithFormat:#"%ld", model.iid]];
}
NSOrderedSet *orderedSet = [NSOrderedSet orderedSetWithArray:head];
headData = [[orderedSet array] mutableCopy];
// NSSet *set = [NSSet setWithArray:left];
// NSArray *array2 = [set allObjects];
// NSLog(#"%#", array2);
NSOrderedSet *orderedSet1 = [NSOrderedSet orderedSetWithArray:left];
NSMutableArray *arrLeft = [[orderedSet1 array] mutableCopy];
//remove duplicate enteries from header array
[leftTableData addObject:arrLeft];
NSMutableArray *right = [[NSMutableArray alloc]init];
for (int i = 0; i < arrLeft.count; i++)
{
NSMutableArray *array = [[NSMutableArray alloc] init];
for (int j = 0; j < headData.count; j++)
{
/* NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF.iid == %ld", [[arrLeft objectAtIndex:i] intValue]];
NSArray *filteredArray = [mainTableData filteredArrayUsingPredicate:predicate];*/
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF.iid == %ld AND SELF.yr == %ld", [[arrLeft objectAtIndex:i] intValue], [[headData objectAtIndex:j] intValue]];
NSArray *filteredArray = [mainTableData filteredArrayUsingPredicate:predicate];
if([filteredArray count]>0)
{
Model *model = [filteredArray objectAtIndex:0];
[array addObject:model.val];
}
}
[right addObject:array];
}
[rightTableData addObject:right];
}
How will I sort the arrays in ascending order?
Please help.
OK, so you have a model object that looks something like this...
#interface Model: NSObject
#property NSNumber *idNumber;
#property NSNumber *year;
#property NSString *value;
#end
Note, I am intentionally using NSNumber and not NSInteger for reasons that will become clear.
At the moment you are trying to do a lot all in one place. Don't do this.
Create a new object to store this data. You can then add methods to get the data you need. Seeing as you are displaying in a table view sectioned by year and then each section ordered by idNumber then I'd do something like this...
#interface ObjectStore: NSObject
- (void)addModelObject:(Model *)model;
// standard table information
- (NSInteger)numberOfYears;
- (NSInteger)numberOfIdsForSection:(NSinteger)section;
// convenience methods
- (NSNumber *)yearForSection:(NSInteger)section;
- (NSNumber *)idNumberForSection:(NSInteger)section row:(NSInteger)row;
- (NSArray *)modelsForSection:(NSInteger)section row:(NSInteger)row;
// now you need a way to add objects
- (void)addModelObject:(Model *)model;
#end
Now to implement it.
We are going to store everything in one dictionary. The keys will be years and the objects will be dictionaries. In these dictionaries the keys will be idNumbers and the objects will be arrays. These array will hold the models.
So like this...
{
2010 : {
1 : [a, b, c],
3 : [c, d, e]
},
2013 : {
1 : [g, h, u],
2 : [e, j, s]
}
}
We'll do this with all the convenience methods also.
#interface ObjectStore: NSObject
#property NSMutableDictionary *objectDictionary;
#end
#implementation ObjectStore
+ (instancetype)init
{
self = [super init];
if (self) {
self.objectDictionary = [NSMutableDictionary dictionary];
}
return self;
}
+ (NSInteger)numberOfYears
{
return self.objectDictionary.count;
}
+ (NSInteger)numberOfIdsForSection:(NSinteger)section
{
// we need to get the year for this section in order of the years.
// lets create a method to do that for us.
NSNumber *year = [self yearForSection:section];
NSDictionary *idsForYear = self.objectDictionary[year];
return idsForYear.count;
}
- (NSNumber *)yearForSection:(NSInteger)section
{
// get all the years and sort them in order
NSArray *years = [[self.obejctDictionary allKeys] sortedArrayUsingSelector:#selector(compare:)];
// return the correct year
return years[section];
}
- (NSNumber *)idNumberForSection:(NSInteger)section row:(NSInteger)row
{
// same as the year function but for id
NSNumber *year = [self yearForSection:section];
NSArray *idNumbers = [[self.objectDictionary allKeys]sortedArrayUsingSelector:#selector(compare:)];
return idNumbers[row];
}
- (NSArray *)modelsForSection:(NSInteger)section row:(NSInteger)row
{
NSNumber *year = [self yearForSection:section];
NSNumber *idNumber = [self idForSection:section row:row];
return self.objectDictionary[year][idNumber];
}
// now we need a way to add objects that will put them into the correct place.
- (void)addModelObject:(Model *)model
{
NSNumber *modelYear = model.year;
NSNumber *modelId = model.idNumber;
// get the correct storage location out of the object dictionary
NSMutableDictionary *idDictionary = [self.objectDictionary[modelYear] mutableCopy];
// there is a better way to do this but can't think atm
if (!idDictionary) {
idDictionary = [NSMutableDictionary dictionary];
}
NSMutableArray *modelArray = [idDictionary[modelId] mutableCopy];
if (!modelArray) {
modelArray = [NSMutableArray array];
}
// insert the model in the correct place.
[modelArray addObject:model];
idDictionary[modelId] = modelArray;
self.objectDictionary[modelYear] = idDictionary;
}
#end
With all this set up you can now replace your complex function with this...
-(void) requestFinished: (ASIHTTPRequest *) request
{
NSString *theJSON = [request responseString];
SBJsonParser *parser = [[SBJsonParser alloc] init];
NSDictionary *jsonDictionary = [parser objectWithString:theJSON error:nil];
for (NSDictionary *dictionary in jsonDictionary)
{
Model *model = [[Model alloc]init];
model.cid = [dictionary valueForKey:#"cid"];
model.idNumber = [dictionary valueForKey:#"iid"];
model.year = [dictionary valueForKey:#"yr"];
model.val = [dictionary valueForKey:#"val"];
[self.objectStore addModelObject:model];
}
}
To get the models out for a particular row then just use...
[self.objectStore modelsForSection:indexPath.section row:indexPath.row];
To get the number of sections in the tableview delegate method...
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [self.objectStore numberOfYears];
}
No messing around with the model in the view controller.
Welcome to the MVC pattern.
There's a crap ton of code here but by placing all the code here you can remove all the complex code from your VC.
NSSet keeps only non-duplicate objects within themselves so to keep only unique objects in array you can use NSSet as -
Suppose you have array with duplicate objects
NSArray *arrayA = #[#"a", #"b", #"a", #"c", #"a"];
NSLog(#"arrayA is: %#", arrayA);
//create a set with the objects from above array as
//the set will not contain the duplicate objects from above array
NSSet *set = [NSSet setWithArray: arrayA];
// create another array from the objects of the set
NSArray *arrayB = [set allObjects];
NSLog(#"arrayB is: %#", set);
The output from the above looks like:
arrayA is: (
a,
b,
a,
c,
a
)
arrayB is: {(
b,
c,
a
)}
and to sort a mutable array in ascending order you can use NSSortDescriptor and sortUsingDescriptors:sortDescriptors. Also you need to provide the key on the basis of which array will be sorted.
NSSortDescriptor *sortDescriptor;
sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"key" ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
[array sortUsingDescriptors:sortDescriptors];
[sortDescriptor release];
Here you will get what you want.
//sort description will used to sort array.
NSSortDescriptor *descriptor=[[NSSortDescriptor alloc] initWithKey:#"iid" ascending:YES];
NSArray *descriptors=[NSArray arrayWithObject: descriptor];
NSArray *reverseOrder=[arrLeft sortedArrayUsingDescriptors:descriptors];
reverseOrder is your desire output.
there is another way you can sort objects that followed model.
NSArray *someArray = /* however you get an array */
NSArray *sortedArray = [someArray sortedArrayUsingComparator:^(id obj1, id obj2) {
NSNumber *rank1 = [obj1 valueForKeyPath:#"iid"];
NSNumber *rank2 = [obj2 valueForKeyPath:#"iid"];
return (NSComparisonResult)[rank1 compare:rank2];
}];
here sortedArray is our output.
you can replace same things for yr key as well.
This is what I did to sort the header data in ascending order and to remove duplicates from both header and leftmost column. Hope this will help others
NSOrderedSet *orderedSet3 = [NSOrderedSet orderedSetWithArray:head3];
headData3 = [[orderedSet3 array] mutableCopy];
[headData3 sortUsingComparator:^NSComparisonResult(NSString *str1, NSString *str2)
{
return [str1 compare:str2 options:(NSNumericSearch)];
}];
NSOrderedSet *orderedSet4 = [NSOrderedSet orderedSetWithArray:left3];
NSMutableArray *arrLeft3 = [[orderedSet4 array] mutableCopy];
[leftTableData3 addObject:arrLeft3];
I have code that works but then I would have to add a new array and new code for every new country that my app will support and it is probably highly inefficient, as this code has to be run before the app starts and the view appears.
- (NSMutableDictionary *)retrieveDictionaryOfCountryAndCompany {
NSMutableDictionary *companyAndCountry = [[NSMutableDictionary alloc] init];
NSMutableArray *countryNames = [[NSMutableArray alloc] init];
NSMutableArray *germanyArray = [[NSMutableArray alloc] init];
NSMutableArray *englandArray = [[NSMutableArray alloc] init];
PFQuery *companyQuery = [PFQuery queryWithClassName: #"Company"];
NSArray *objects = [companyQuery findObjects];
for (PFObject *object in objects) {
if ([[object valueForKey:#"country"] isEqual: #"Germany"]) {
[germanyArray addObject:[object valueForKey:#"name"]];
}
[countryNames addObject:[object valueForKey:#"country"]];
}
NSSet *uniqueItems = [NSSet setWithArray:germanyArray];
germanyArray = [[uniqueItems allObjects] mutableCopy];
uniqueItems = [NSSet setWithArray:countryNames];
countryNames = [[uniqueItems allObjects] mutableCopy];
[germanyArray sortUsingSelector:#selector(localizedCaseInsensitiveCompare:)];
[countryNames sortUsingSelector:#selector(localizedCaseInsensitiveCompare:)];
[companyAndCountry setObject:germanyArray forKey:#"Germany"];
[companyAndCountry setObject:countryNames forKey:#"country"];
return companyAndCountry;
}
Is there a better solution that I'm not seeing because it's too simple? Thanks for your help.
Unless I'm being dense:
- (NSMutableDictionary *)retrieveDictionaryOfCountryAndCompany {
NSMutableArray *countryNames = [NSMutableArray array];
NSMutableDictionary *companyAndCountry =
[#{ #"country" : countryNames } mutableCopy];
PFQuery *companyQuery = [PFQuery queryWithClassName: #"Company"];
NSArray *objects = [companyQuery findObjects];
for (PFObject *object in objects) {
NSString *countryName = [object valueForKey:#"country"];
NSString *placeName = [object valueForKey:#"name"];
if(!countryName || !placeName) continue; // a malformed record
[countryNames addObject:countryName];
NSMutableSet *namesInCountry = companyAndCountry[countryName];
if(!namesInCountry)
{
namesInCountry = [NSMutableSet set];
companyAndCountry[countryName] = namesInCountry;
}
[namesInCountry addObject:placeName];
}
for (NSString *key in [[companyAndCountry allKeys] copy])
{
NSArray *sortedArray =
[[companyAndCountry[key] allObjects]
sortedArrayUsingSelector:
#selector(localizedCaseInsensitiveCompare:)];
companyAndCountry[key] = sortedArray;
}
return companyAndCountry;
}
So just create and populate the lists on demand, initially as sets to avoid some of the array -> set -> array -> sorted array shuffle at the end.
As to performance, Parse is a web service so this should all be done asynchronously. Is that the case?
NSArray*arr = #[#"ram",#"Ram",#"vinoth",#"kiran",#"kiran"];
NSSet* uniqueName = [[NSSet alloc]initWithArray:arr];
NSLog(#"Unique Names :%#",uniqueName);
Output:
but i need the output as
You could first convert them all to lowercase strings.
NSArray *arr = #[#"ram",#"Ram",#"vinoth",#"kiran",#"kiran"];
NSArray *lowerCaseArr = [arr valueForKey:#"lowercaseString"];
NSSet* uniqueName = [[NSSet alloc] initWithArray:lowerCaseArr];
NSLog(#"Unique Names :%#",uniqueName);
Unique Names :{(
ram,
kiran,
vinoth
)}
Try this:
NSArray *arr = [NSArray arrayWithObjects:#"Ram",#"ram", nil]; //this is your array
NSMutableArray *arr1 = [[NSMutableArray alloc]init]; //make a nsmutableArray
for (int i = 0; i<[arr count]; i++) {
[arr1 addObject:[[arr objectAtIndex:i]lowercaseString]];
}
NSSet *set = [NSSet setWithArray:(NSArray*)arr1];//this set has unique values
This will always preserve casing form that was existing in your original container (although it's undefined which casing):
NSArray<NSString*>* input = ...
NSMutableDictionary* tmp = [[NSMutableDictionary alloc] init];
for (NSString* s in input) {
[tmp setObject:s forKey:[s lowercaseString]];
}
return [tmp allValues];
Create a mutable array the same size as arr. Fill it with lowercaseString versions of each element of arr. Make the set out of that.
#Updated
Using this you remove uppercase string from your array.
NSMutableArray *arr= [[NSMutableArray alloc]initWithObjects:#"ram",#"Ram",#"vinoth",#"kiran", nil];
NSMutableArray *arrCopy = [[NSMutableArray alloc]init];
for (int index = 0 ; index<arr.count; index++) {
NSUInteger count = [[[[arr objectAtIndex:index] componentsSeparatedByCharactersInSet:[[NSCharacterSet uppercaseLetterCharacterSet] invertedSet]] componentsJoinedByString:#""] length];
if (count == 0) {
[arrCopy addObject:[arr objectAtIndex:index]];
}
}
NSLog(#"Print Mutable Copy %#",arrCopy);
try this one
NSArray *copyArray = [mainArray copy];
NSInteger index = [copyArray count] - 1;
for (id object in [copyArray reverseObjectEnumerator]) {
if ([mainArray indexOfObject:object inRange:NSMakeRange(0, index)] != NSNotFound) {
[mainArray removeObjectAtIndex:index];
}
index--;
}
copyArray=nil;
In my code, I set array inside a NSMutableDictionary as
if (array.count > 0) {
[self.filters setValue:array forKey:[self getKey:[[NSNumber numberWithInt:indexPath.section] intValue]]];
}
where array is
NSMutableArray *array = [[NSMutableArray alloc] init];
When the receiving code receives it, I tried to join the values in array as
if ([item objectForKey:#"category_filter"] != nil) {
NSArray *array = [NSArray arrayWithObjects:[item objectForKey:#"category_filter"], nil];
NSString *categories = [array componentsJoinedByString:#","];
NSLog(#"value:%#", categories);
}
where item is (NSMutableDictionary *)item
When I see log, I see as
2014-06-24 17:43:12.520 yelp[69744:70b] value:(
"Bagels (bagels)",
"Bakeries (bakeries)"
)
so they are not joined yet. What am I doing wrong here?
As Hot Licks commented,
I had to make change as
NSArray *array = [NSArray arrayWithArray:[item objectForKey:#"category_filter"]];
instead of
NSArray *array = [NSArray arrayWithObjects:[item objectForKey:#"category_filter"]];