First off i have searched a lot but all methods seems to be for primitives or for whole custom objects.
My situation is this. I have a type custom objects in two different arrays. However the fields of every single objects is quite different to another with the exception of only 2 fields.
What i want is combine both of these arrays and then remove duplicates with respect to only those two fields.How can i do that. My Code so far
NSMutableArray* testArray = [eventHandler returnAllEvents];
NSMutableArray* combinedArray = [[NSMutableArray alloc]init];
NSArray* finalArray = [[NSArray alloc]init];
if (testArray.count==0) {
for (int i = 0; i<facebookData.count; i++) {
LSEvent* event = [facebookData objectAtIndex:i];
[combinedArray addObject:event];
}
finalArray = [combinedArray arrayByAddingObjectsFromArray:calendarData];
}
NSMutableArray *uniqueArray = [NSMutableArray array];
NSMutableSet *names = [NSMutableSet set];
for (id obj in finalArray) {
NSString *destinationName = [obj destinationname];
if (![names containsObject:destinationName]) {
[uniqueArray addObject:obj];
[names addObject:destinationName];
}
}
You can do sth like this
NSArray first = ...
NSMutableArray second = ... // this will be combine array
for (id someObj in first) {
if ( [second filteredArrayUsingPredicate:[self predicateForObject:someObj ]].count == 0 ){
[second addObject: someObj];
}
}
If you want to check that object exists in array using containsObject: you need to implement - (BOOL)isEqual:(id)other in your custom object.
- (BOOL)isEqual:(id)other {
if (other == self) {
return YES;
}
if (!other || ![other isKindOfClass:[self class]]) {
return NO;
}
if (self.identifier == other.identifier) {
return NO;
}
return YES;
}
Related
I am sorting an array.
There are three types of elements in the array.
1. featured
2. organic and
3. claimed.
Among them, I want to sort only organic elements and keep the featured and claimed elements at their own index.
Below is my code in which, I am extracting the claimed and featured indices in a dictionary as key being the index and value is the array element.
//Initialization
NSMutableArray *sortedArray = nil;
NSMutableDictionary *tempFeaturedDictionary = [[NSMutableDictionary alloc]init];
NSMutableDictionary *tempClaimedDictionary = [[NSMutableDictionary alloc]init];
NSMutableArray *tempOrganicArray = [[NSMutableArray alloc]init];
for (int i = 0; i < array.count; i++) {
DRListing *isFeaturedObj = (DRListing*)[array objectAtIndex:i];
if (isFeaturedObj.featured) {
[tempFeaturedDictionary setObject:isFeaturedObj forKey:[#(i)stringValue]];
}else if (isFeaturedObj.claimed)
{
[tempClaimedDictionary setObject:isFeaturedObj forKey:[#(i)stringValue]];
}else
[tempOrganicArray addObject:isFeaturedObj];
}
Again I am adding the claimed and featured back to their original indices after sorting as:
sortedArray = [NSMutableArray arrayWithArray:[tempOrganicArray sortedArrayUsingDescriptors:sortDescriptorsArray]];
for (int i = 0; i<sortedArray.count; i++) {
for (NSString *key in tempFeaturedDictionary) {
if ( [[#(i)stringValue] isEqualToString: key] ) {
[sortedArray insertObject:[tempFeaturedDictionary objectForKey:[#(i)stringValue]] atIndex:i];
}}
for (NSString *key in tempClaimedDictionary) {
if ([[#(i)stringValue]isEqualToString:key ]) {
[sortedArray insertObject:[tempClaimedDictionary objectForKey:[#(i)stringValue]] atIndex:i];
}
}
}
The code works good. Except there is claimed/(and)featured elements at the last index of the 'array'. Because the 'sortedArray' index remains less than the 'array.count' in this scenario.
Thanks in advance.
Update -
I receive response array of type:
[{featured1 featured2}, {organic1, organic2..}, {claimed1}, {featured11, featured12}, {organic11, organic12..}, {claimed2}, ..]
and I am allowed to sort only organic elements within this array. Featured and claimed should not loose their original index position.
I would iterate through the array, extracting the organics to sort. Then sort your organic array. Then iterate through the original array taking either the element from the original array or an element from the sorted organics array as appropriate.
NSMutableArray *organicsArray = [NSMutableArray new];
for (int i = 0; i < array.count; i++) {
DRListing *isFeaturedObj = (DRListing*)array[i];
if ((!isFeaturedObj.featured) && (!isFeaturedObj.claimed)) {
[organicsArray addObject:isFeaturedObj];
}
}
NSMutableArray *sortedOrganicsArray = [[organicsArray sortedArrayUsingDescriptors:sortDescriptorsArray] mutableCopy];
NSMutableArray *outputArray = [NSMutableArray new];
for (int i = 0; i < array.count; i++) {
DRListing *isFeaturedObj = (DRListing*)array[i];
if ((!isFeaturedObj.featured) && (!isFeaturedObj.claimed)) {
[outputArray addObject:sortedOrganicsArray[0]];
[sortedOrganicsArray removeObjectAtIndex:0];
} else {
[outputArray addObject:isFeaturedObject];
}
}
You could possibly make it a little more efficient if you reversed your sort order for the organics array since then you could say
[outputArray addObject:[sortedOrganicsArray lastObject]];
[sortedOrganicsArray removeLastObject];
But if your array isn't particularly large then the performance improvement will probably be negligible.
Maybe this is an alternative:
NSMutableArray *organics = [NSMutableArray new];
NSMutableArray *others = [NSMutableArray new];
for (DRListing *isFeaturedObj in array) {
if (isFeaturedObj.organic) {
[organics addObject:isFeaturedObj];
} else {
[others addObject:isFeaturedObj];
}
}
NSMutableArray *sorted = [NSMutableArray alloc]initWithObjects:organics,others, nil];
You can take the first 2 functions. The others are what I used for testing.
- (DRListing *)getNextObjectFromArray:(NSArray *)array WithStartingIndex:(int)index
{
for (int i=index; i<array.count; i++) {
DRListing *obj = (DRListing*)[array objectAtIndex:i];
if (!obj.featured && !obj.claimed)
{
return obj;
}
}
return nil;
}
- (void)sortArray:(NSMutableArray *)array
{
for (int pass = 0; pass<array.count-1; pass++) {
for (int i=0; i<array.count-1; i++) {
DRListing *obj = [self getNextObjectFromArray:array WithStartingIndex:i];
int foundIndex = (int)[array indexOfObject:obj];
DRListing *obj2 = [self getNextObjectFromArray:array WithStartingIndex:foundIndex+1];
int foundIndex2 = (int)[array indexOfObject:obj2];
if (obj!=nil && obj2 !=nil) {
if (obj.value >= obj2.value) {
[array exchangeObjectAtIndex:foundIndex withObjectAtIndex:foundIndex2];
}
i = foundIndex;
}
}
}
NSLog(#"Sorted Data: %#",array);
}
- (NSMutableArray *)testData
{
NSMutableArray *array = [NSMutableArray new];
for (int i=0; i<20; i++) {
DRListing *obj = [DRListing new];
obj.featured = i*i%2;
obj.claimed = i%2;
obj.value = i*3%10;
[array addObject:obj];
}
NSLog(#"Test Data: %#",array);
return array;
}
#interface DRListing : NSObject
#property (nonatomic) BOOL featured;
#property (nonatomic) BOOL claimed;
#property (nonatomic) int value;
#end
Here is my requirement :
forSaleSingleProperties array should contain dictionaries with no same attribute PARCELID
forSaleMultipleProperties array should contain an array of those dictionaries with same attribute PARCELID
forSalePropertiesArray is the base array containing all dict.
Note: Dictionaries contain various other attributes. I want all those with same PARCELID attribute
I don't understand what is wrong with this logic...
if (_forSaleSinglePropertiesArray==nil) {
_forSaleSinglePropertiesArray = [[NSMutableArray alloc]initWithObjects: nil];
}
if (_forSaleMultiplePropertiesArray==nil) {
_forSaleMultiplePropertiesArray = [[NSMutableArray alloc]initWithObjects: nil];
}
if (_forSalePropertiesArray!=nil) {
if (_forSalePropertiesArray.count>1) {
BOOL propertyObject1IsMultiple = NO;
NSDictionary *propertyObject1;
NSMutableArray *multiplePinArray = [[NSMutableArray alloc]initWithObjects: nil];
for (int i=0; i<_forSalePropertiesArray.count; i++) {
propertyObject1 = [_forSalePropertiesArray objectAtIndex:i];
multiplePinArray = nil;
multiplePinArray = [[NSMutableArray alloc]initWithObjects: nil];
for (int j=i+1; j<_forSalePropertiesArray.count; j++) {
NSDictionary *propertyObject2 = [_forSalePropertiesArray objectAtIndex:j];
if ([propertyObject1 valueForKey:PARCEL_ID]==[propertyObject2 valueForKey:PARCEL_ID]) {
if (_forSaleMultiplePropertiesArray.count==0) {
[multiplePinArray addObject:propertyObject2];
propertyObject1IsMultiple = YES;
[_forSaleMultiplePropertiesArray addObject:multiplePinArray];
}else{
BOOL propFound = NO;
NSMutableArray *propArr;
NSInteger index = -1;
for(NSMutableArray *arr in _forSaleMultiplePropertiesArray){
if (![arr containsObject:propertyObject2]&&!propFound) {
[arr addObject:propertyObject2];
propertyObject1IsMultiple = YES;
propFound = YES;
index = [_forSaleMultiplePropertiesArray indexOfObject:arr];
propArr = [[NSMutableArray alloc]initWithArray:arr];
}
}
if (propArr!=nil) {
[_forSaleMultiplePropertiesArray replaceObjectAtIndex:index withObject:propArr];
}
}
}
}
if (!propertyObject1IsMultiple) {
[_forSaleSinglePropertiesArray addObject:propertyObject1];
}
}
}
}
OK so...
I'm leaving this as a placeholder.
Sort the parent array by PARCELID.
Iterate array.
Sort into two piles.
... or something. Will write it later.
I would have done it more like this:
- (void)solution {
self.forSaleSinglePropertiesArray = [[NSMutableArray alloc] init];
self.forSaleMultiplePropertiesArray = [[NSMutableArray alloc] init];
NSDictionary *partitionedProperties = partitionPropertiesByParcelID(self.forSalePropertiesArray);
[self dividePropertiesIntoSingleAndMultiple:partitionedProperties];
}
NSDictionary *partitionPropertiesByParcelID(NSArray *properties) {
NSMutableDictionary *result = [[NSMutableDictionary alloc] init];
for (NSDictionary *property in properties) {
id parcelID = property[PARCEL_ID];
NSMutableArray *parcels = result[parcelID];
if (parcels == nil) {
parcels = [[NSMutableArray alloc] init];
[result setObject:parcels forKey:parcelID];
}
[parcels addObject:property];
}
return result;
}
- (void)dividePropertiesIntoSingleAndMultiple:(NSDictionary *)partitionedProperties {
for (NSArray *properties in partitionedProperties.allValues) {
if (properties.count == 1) {
[self.forSaleSinglePropertiesArray addObject:properties[0]];
}
else {
assert(properties.count > 1);
[self.forSaleMultiplePropertiesArray addObject:properties];
}
}
}
First the code creates a Dictionary where the keys are parcel IDs and the values are arrays of properties with that parcle ID. Then it goes through that dictionary and puts a representative of each parcel ID into either the single or multiple array.
I feel that this code is easier to understand, and I strongly suspect that if you do performance metrics on the above code and your answer, that this code will have better performance over large data sets. I believe this is true because your answer seems to have O(n^2) performance while mine is O(n). (Read up on "Big-O notation" if you aren't sure what this means.)
Also, are you sure that your answer actually works for all data sets? Removing objects out of an array while iterating over it throws up a huge red flag in my book.
I liked #Fogmeister's sort idea so much, I implemented it:
- (void)sortSolultion {
self.forSaleSinglePropertiesArray = [[NSMutableArray alloc] init];
self.forSaleMultiplePropertiesArray = [[NSMutableArray alloc] init];
NSArray *forSaleArray = [self.forSalePropertiesArray sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
return [obj1[PARCEL_ID] compare:obj2[PARCEL_ID]];
}];
id currentParcelID = nil;
self.propertiesWithCurrentParcelID = [[NSMutableArray alloc] init];
for (NSDictionary *property in forSaleArray) {
if (self.propertiesWithCurrentParcelID.count == 0) {
currentParcelID = property[PARCEL_ID];
}
else if (![property[PARCEL_ID] isEqual: currentParcelID]) {
[self placeCurrentPropertiesInCorrectArray];
currentParcelID = property[PARCEL_ID];
}
[self.propertiesWithCurrentParcelID addObject:property];
}
[self placeCurrentPropertiesInCorrectArray];
}
- (void)placeCurrentPropertiesInCorrectArray {
if (self.propertiesWithCurrentParcelID.count > 1) {
[self.forSaleMultiplePropertiesArray addObject:self.propertiesWithCurrentParcelID];
}
else if (self.propertiesWithCurrentParcelID.count == 1) {
[self.forSaleSinglePropertiesArray addObject:self.propertiesWithCurrentParcelID[0]];
}
[self.propertiesWithCurrentParcelID removeAllObjects];
}
This solution has a slightly higher cyclomatic complexity than my previous solution, and indeed it was harder to get it error free than my first one. But this solution has a smaller allocation footprint. Both seem to have the same big-O complexity.
Alright I got it right myself.
Updated Code to a much simpler and fast mechanism below:
if (_forSaleSinglePropertiesArray==nil) {
_forSaleSinglePropertiesArray = [[NSMutableArray alloc]initWithObjects: nil];
}
if (_forSaleMultiplePropertiesArray==nil) {
_forSaleMultiplePropertiesArray = [[NSMutableArray alloc]initWithObjects: nil];
}
if (_forSalePropertiesArray!=nil) {
NSMutableDictionary *samePropsDict = [[NSMutableDictionary alloc]init];
for (NSDictionary* dict in _forSalePropertiesArray) {
NSMutableArray *samePropsArray = [samePropsDict objectForKey:[dict valueForKey:PARCEL_ID]];
if (samePropsArray==nil) {
samePropsArray = [[NSMutableArray alloc]init];
}
[samePropsArray addObject:dict];
[samePropsDict setObject:samePropsArray forKey:[dict valueForKey:PARCEL_ID]];
}
for (NSString *key in [samePropsDict allKeys]) {
NSArray *arr = [samePropsDict objectForKey:key];
if (arr.count>1) {
[_forSaleMultiplePropertiesArray addObject:arr];
}else{
[_forSaleSinglePropertiesArray addObject:[arr firstObject]];
}
}
}
I want to make 1 array that will hold all of the other arrays objects and will look like this
("052-6224754","03-6475075","02-6753231")
my code is:
-(NSMutableArray*) getRecepientsPhones
{
NSMutableArray* phones = [[NSMutableArray alloc]init];
//scroll all choosed contacts and retrieve phones to nsstring
if([recepientsFromContacts count]>0)
for (int i=0; i<[recepientsFromContacts count]; i++)
{
NSMutableArray* tempArray = [[NSMutableArray alloc]init];
if(![[[recepientsFromContacts objectAtIndex:i]objectForKey:#"CPhones"]isKindOfClass:[NSNull class]])
{
[tempArray addObject:[[recepientsFromContacts objectAtIndex:i]objectForKey:#"CPhones"]];
for(int j = 0; j<[tempArray count];j++)
{
[phones addObject:[tempArray objectAtIndex:j]];
}
}
}
//lets fetch from that contact
if([personRecepient count]>0)
{
if(![[personRecepient objectForKey:#"CellPhone"]isKindOfClass:[NSNull class]])
[phones addObject:[personRecepient objectForKey:#"CellPhone"]];
}
NSLog(#"%#",phones);
return phones;
}
[[recepientsFromContacts objectAtIndex:i]objectForKey:#"CPhones"]
is 1 or more dimension array (it is array of phone numbers per person , person can have more than 1 number)
example: ("052-6224754","03-6475075")
but my function returns
("052-6224754","03-6475075"),("02-6753231")
which is not good , what should I do to make it 1 array
("052-6224754","03-6475075","02-6753231")
You should change the line
[phones addObject:[tempArray objectAtIndex:j]];
to
[phones addObjectsFromArray:[tempArray objectAtIndex:j]];
This should result in a flattened array of phone numbers.
Then you should head over to codereview.stackexchange.com because there are several issues with your code fragment.
Edit: Here's a cleaned up version of the method:
- (NSArray *)recepientsPhoneNumbers
{
NSMutableArray* phoneNumbers = [NSMutableArray array];
for (NSDictionary *dict in _recepientsFromContacts)
{
id recipientPhoneNumbers = dict[#"CPhones"];
if (recipientPhoneNumbers != [NSNull null])
[phoneNumbers addObjectsFromArray:recipientPhoneNumbers];
}
id recipientPhoneNumbers = _personRecepient[#"CellPhone"];
if (recipientPhoneNumbers != [NSNull null])
[phoneNumbers addObjectsFromArray:recipientPhoneNumbers];
NSLog(#"%#", phoneNumbers);
return phoneNumbers;
}
I applied Cocoa coding conventions, so ivars are now prefixed with underscores.
I need to compare two arrays (A & B), than for the elements of A that belong also to B I need to set an if statement. Just to explain me better:
if (elementOfArrayA belong AlsoToarrayB) {
//do something
}else{
//do something else
}
Someone could help me?
Thanks
NSArray has an instance method called containsObject: exactly for this.
For further clarification, check this out.
Use following code to compare two array :
NSArray *array1 = [[NSArray alloc] initWithObjects:#"a",#"b",#"c",nil];
NSArray *array2 = [[NSArray alloc] initWithObjects:#"a",#"d",#"c",nil];
for(int i = 0;i<[array1 count];i++)
{
for(int j= 0;j<[array2 count];j++)
{
if([[array1 objectAtIndex:i] isEqualToString:[array2 objectAtIndex:j]])
{
} else {
}
}
}
Comparing two arrays:
if([arrayA isEqualToArray:arrayB]){
//the two arrays A and B are equals
}
The code above will test ALL elements of both arrays to check if they fulfill the isEqual test, so no need to for loop the array.
If you want to check wether an element of arrayA is contained in arrayB, use the following method:
id firstCommonObject = [arrayA firstObjectCommonWithArray:arrayB];
if(firstCommonObject != nil){
//a common object between arrayA and arrayB has been found
}else{
//no common objects between both arrays
}
// Method 1 - Simplest method to solve above problem (Use NSArray's containsObject method)
NSArray *array1 = [[NSArray alloc] initWithObjects:#"a",#"b",#"c",#"e", nil];
NSArray *array2 = [[NSArray alloc] initWithObjects:#"a",#"d",#"c",#"f", nil];
for(id i in array1){
if ([array2 containsObject:i]) {
// do something
}
else {
// do something else
}
}
// Method 2 - Another method (Use NSString's isEqualToString method)
NSArray *array1 = [[NSArray alloc] initWithObjects:#"a",#"b",#"c",#"e", nil];
NSArray *array2 = [[NSArray alloc] initWithObjects:#"a",#"d",#"c",#"f", nil];
for(id i in array1){
for(id j in array2){
if ([i isEqualToString:j]) {
// do something
}
else {
//do something else
}
}
}
it may be help you...
-(void)methodFour
{
NSArray *arr1 = [[NSArray alloc]initWithObjects:#"a2223a",#"ab33b",#"a1acdf",#"ac23c45", nil];
NSArray *arr11 = [arr1 sortedArrayUsingSelector:#selector(localizedCompare:)];
NSLog(#"%#",arr11);
NSArray *arr2 = [[NSArray alloc]initWithObjects:#"ab33b",#"ac23c45",#"a1acdf",#"a2223a", nil];
NSArray *arr22= [arr2 sortedArrayUsingSelector:#selector(localizedCompare:)];
[self firstArray:arr11 secondArray:arr22];
}
-(void)firstArray:(NSArray *)array1 secondArray:(NSArray *)array2
{
if ([array1 isEqualToArray:array2])
{
NSLog(#"equal");
}
else
{
NSLog(#"Not equal");
}
}
I made the following method to remove doubles, however it doesn't fully work. Any suggestions?
Thank you for the help,
-(NSMutableArray*)removeDuplicateCars:(NSMutableArray*)array{
NSMutableArray *noDuplicates =[[NSMutableArray alloc]init];
for (int i=0; i<[array count]; i++) {
int counter =0;
Car *car =(Car*)[array objectAtIndex:i];
if ([noDuplicates count]==0) {
[noDuplicates addObject:car];
}
for (int i=0; i<[noDuplicates count]; i++) {
Car *car2 =(Car*)[array objectAtIndex:i];
if (![car.name isEqualToString:car2.name]) {
counter++;
}
}
if (counter==[noDuplicates count]) {
[noDuplicates addObject:car];
}
}
NSLog(#"number of results = %i",[noDuplicates count]);
return noDuplicates;
}
Create an array called "addedCars" - you will use it to store the name of each unique car.
In each iteration, use [NSArray containsObject:] to check if the current name has already been added to "addedCars". If not, add the name to "addedCars" and the car to "noDuplicates". Otherwise, skip this item, as it has already been added to noDuplicates.
be sure [isEqual:] and [hash] is implemented as you expected
-(NSMutableArray*)removeDuplicateCars:(NSMutableArray*)array{
NSOrderedSet *set = [[NSOrderedSet alloc] initWithArray:array];
NSMutableArray *newArr = [NSMutableArray arrayWithCapacity:[set count]];
for (id obj in set) {
[newArr addObject:obj];
}
return newArr;
}
You used ![car.name isEqualToString:car2.name] to compare objects so I believe you want to filter objects with same name? Than you need to override [isEqual:] for Car
- (BOOL)isEqual:(id)other {
if ([other isKindOfClass:[self class]]) {
return [self.name isEuqalToString: [other name]];
}
return NO;
}
- (NSUInteger)hash {
return [self.name hash];
}
also check this question The best way to remove duplicate values from NSMutableArray in Objective-C?