Creating an array based on multiple conditions - objective-c

This is more of a logic question. I wanted to see different approaches.
I am trying to create a filter array based on multiple criteria. Let's say I have 4 boolean criteria,
I will set these with a simple toggle button.
NSObject* A; BOOL booleanA TRUE;
NSObject* B;BOOL booleanB FALSE;
NSObject* C;BOOL booleanC TRUE;
NSObject* D;BOOL booleanD FALSE;
What I want to achieve is to end up with an array with objects with TRUE boolean values like :
NSArray: {A, C}
I was going to use the most straightforward approach:
if(booleanA)[array addObject:A];
if(booleanB)[array addObject:B];
if(booleanC)[array addObject:C];
if(booleanD)[array addObject:D];
Looks fine to me, but maybe you can come up with something different and simpler. I literally cant think of any other way.

You look for an algorithmic solution. Right now, you manually transform 4 (unrelated, albeit similar named) BOOLs into 1 array. You can only write an algorithm when there's a 1:1 match, instead of a N:1 transformation. So I suggest you try to put booleanA to booleanD in a container instead of fiddling around with seemingly unrelated variables.
If you put the booleans into an array with fixed positions, using consts or macros for the indexes (booleans[B_INDEX]), you can write an algorithm to transform the truthiness at index i into letter A+i, so to speak.
If you use a small collection class instead, you can even get rid of handling arrays and matching indexes.
I would prefer a collection class so that the other class using this stuff doesn't get too bloated. The four lines you show look similar, but since the BOOLs have nothing in common but their name, you won't be able to write an algorithm yet. Encapsulating an algorithm like #user3571918 proposed will hide the matching from your calling class. Also, it hides the fact that 4 lines of manual transformation may have turned into a 30+ lines value object or service class :)
Will using a more complex, algorithmic solution pay off? I think this is the case if you plan on adding more switches later so you don't have to change the calling class just because its data representation was extended.
Example code
Here's an example algo I'd put into a utility class to hide the fact that the number of elements is fixed from other classes.
NSArray *booleans = #[#0, #1, #0, #1]; // array representation
NSArray *transformations = #[#"A", #"B", #"C", #"D"]; // matching utility
NSMutableArray *result = [NSMutableArray array];
[booleans savedArray enumerateObjectsUsingBlock:^(NSNumber *boolean, NSUInteger idx, BOOL *stop) {
BOOL isToggled = [boolean booleanValue];
id transformation = transformations[idx];
if (isToggled)
{
[result addObject:transformation];
}
}];
// result will be: #[#"B", #"D"];
How you assemble booleans depends on the code you already have. Maybe handing the toggle switches over as a variadic argument list to a utility method works, maybe it will be simpler.

The issue is that a Boolean operator is not an object. You might be better off utilizing #0 and #1 for your purposes, and no matter what you'd have to objectify your Boolean value to place in NSArray. The workaround for that is to utilize a C array, however, since you asked for a more convenient way to derive your answer utilizing Objective-C, I'll stick with that.
Basically, I think your question boils down to 'how to enumerate NSArray' and there are some options. Here's a good high level resource regarding NSArray. There are other ways to do it, and especially flexible with enumerateWithBlock as described here previously.
With fast enumeration you can have code that may look similar to the following:
NSArray* array = #[#0, #1, #0, #1];
for (NSNumber* number in array) {
if ([number isEqualToNumber:#0]) {
// action here
return;
}
// else action here
}

Related

Return a key : value pair from a method for use in NSDictionary

I understand I can return an NSDictionary by doing
- (NSDictionary *)keyWithValue {
return #{#"key" : #"value"};
}
but how can I return that without the enclosing #{} dictionary?
There is no tuples in Objective C unlike in Swift, Python etc. So the common way to return 2 different objects is to return an array or a dictionary.
You also can try something like:
- (NSString *)keyWithValue:(NSString**)value {
*value = #"value";
return #"key";
}
It should be used following way:
NSString *v;
NSString *k = [self keyWithValue:&v];
// now v contains #"value"
Objective-C, like C before it, doesn't allow the return of multiple values from a method. (Essentially, although a method or function can accept any number of arguments as input, it can only have a single return value.) There are historical and implementation reasons for this design but it can be frustrating when you simply have a pair/tuple to return.
If you have a method that has two distinct "results" that you need to return to the caller, you have a few choices. The very simplest in your case is to do something like what you are doing here and "wrapping" the values in a dictionary. You could similarly wrap them in a two-value array (which is a little less good since it relies on an implicit contract between caller and callee that there will be exactly two items in the array).
However, a clean and fairly standard approach here would be to create a small class with only two properties on it, and create, fill in, and return that instance with your pair of values. This arguably uses less runtime overhead than a collection object, and has the nice benefit of being semantically explicit and easy to understand for anyone else looking at it.
(There is yet another way, which involves passing pointers as arguments that are "outparams", but that's only idiomatic in rare circumstances in ObjC and I wouldn't recommend it here.)
There is no way to return a key value pair without a dictionary because that is the definition of the dictionary data structure. From apple docs:
The NSDictionary class declares the programmatic interface to objects that manage immutable associations of keys and values
You access the value with
[myDictionary objectForKey:#"myKey"];
If you want to use the returned key-value pair in another dictionary
NSMutableDictionary *otherDict = [NSMutableDictionary alloc] init];
[otherDict setObject:[myDictionary objectForKey:#"myKey"] forKey:#"myKey"];

Overriding isEqual: so that different objects can equal the same object (sort of)

So I have a situation where im using a class as a kind of struct. now i want to override the isEqual: method so if this type of object is inside an array, i can use [objects indexOfObject:obj]
but, now say obj contains objects called duck, and chicken, i would like to go [objects indexOfObject:duck] and it will actually give me the index of obj
so i tried something like this:
- (BOOL)isEqual:(id)anObject {
if([anObject isKindOfClass:[Duck class]]){
return [anObject isEqual:_duck];
}
else if([anObject isKindOfClass:[Chicken class]]){
return [anObject isEqual:_chicken];
}
return [anObject isEqual:self];
}
which doesnt work and isnt even getting called... think that has to do with overriding hash, which i tried by just returning self.hash (effectively obj.hash) but that didnt work.
Do you think something like this is possible? or should i just use for loops to search through all my obj's to find which duck is contained in which obj and return the index of it (which i can do, just wanted to try be cool and neat at the same time)
It sounds using -isEqual: is a bad idea here.
You can't have a DuckAndChicken that compares equal to its Duck and its Chicken, (and vice versa) because in order to stay consistent, all ducks and chickens would then have to compare equal.
Example:
duck1 + chicken1 compares equal to duck1
chicken1 compares equal to duck1 + chicken1
duck2 + chicken1 compares equal to chicken1
duck2 compares equal to duck1
Universe explodes
The good news is that you don't have to use -indexObject: to retrieve from the array. NSArray has a handy -indexOfObjectPassingTest: method that should do what you want.
[ducksAndChickens indexOfObjectPassingTest:^BOOL(DuckAndChicken *obj, NSUInteger idx, BOOL *stop) {
if ([obj.duck isEqual:myDuck]) {
// woop woop...
}
}];
Yes, it sounds like a hash issue.
I would avoid trying to do this by overriding isEqual: because you're liable to break things that you don't think you'd break.
Instead add a custom method that you can call to determine your version of equivalence. Then have a helper method or a category on NSArray which adds my_indexOfObject: and does the iteration.
Its hard to tell what you really want to do from your example but could you perhaps have two dictionaries one where ducks are the key and one where chickens are the key and the object value is either the actual parent object or a NSNumber with the index in the array. This would make lookup much quicker though would take up more memory, and could make synchronisation between the three data structs.

Strange for loops I'm not familiar with: "for (id * in *)"

I apologize if this question is exceedingly simple, but I've Googled like crazy and am unable to find a suitable explanation for what this is.
for (id line in self.lines){
[linesCopy addObject:[line copyWithZone:zone]];
}
I'm just learning Objective-C, and this is a form of for loop that I've never seen before. I'm familiar with the simple
for (int x = 1, x < 10, x++)
style of for loop.
From Cocoa Core Competencies: Enumeration:
Fast Enumeration
Several Cocoa classes, including the collection classes, adopt the NSFastEnumeration protocol. You use it to retrieve elements held by an instance using a syntax similar to that of a standard C for loop, as illustrated in the following example:
NSArray *anArray = // get an array;
for (id element in anArray) {
/* code that acts on the element */
}
As the name suggests, fast enumeration is more efficient than other forms of enumeration.
In case you didn't know, id is an Objective-C type that basically means “a pointer to any Objective-C object”. Note that the pointer-ness of id is built in to it; you usually do not want to say id *.
If you expect the elements of anArray to be of a specific class, say MyObject, you can use that instead:
for (MyObject *element in anArray) {
/* code that acts on the element */
}
However, neither the compiler nor the runtime will check that the elements are indeed instances of MyObject. If an element of anArray is not an instance of MyObject, you'll probably end up trying to send it a message it doesn't understand, and get a selector-not-recognized exception.
It's the shorthand equivalent of this common form:
for (int i = 0; i < [self.lines count]; i++) {
id line = [self.lines objectAtIndex:i];
// ...
}
It's such a common looping idiom (walking through some collection, array, set, etc. an item at a time), that it's been turned into a shorthand form like this, called "fast enumeration".
In fact, in its internal implementation, it's actually slightly more faster than doing it yourself, so it's preferable both for clarity and performance.
It's a statement that can be used with classes that are conform to NSFastEnumeration protocol. When you have this available, the Objective-C programming guide suggest you to use it. Take a look here. It's a way to iterate over a collection without the traditional for (int i = 0; i < length; ++i) syntax.
Mind that it doesn't usually support deleting and inserting elements while iterating through this way (also by using normal for loops you should take care about indices in any case).
Basically all standard collections supports this way of iteration.
It's called a forin loop, also called fast enumeration. Basically, the syntax is:
for (SomeObjectIAmExpecting *localVariableName in anArrayOfObjects)
{
if (![localVariableName isKindOfClass:[SomeObjectIAmExpecting class]]) continue; //To avoid errors.
//do something to them
}

Comparing NSSets by a single property

I'm trying to determine if two NSSets are "equal" but not in the sense of isEqualToSet. Items in the two sets are the same class but are not the same object, or even references to the same object. They will have one property that is the same though - let's call it 'name'.
Is my best bet in comparing these two sets to do a simple set count test, then a more complex objectsPassingTest: on each item in one set, making sure an item with the same name is in the other set? I'm hoping that something simpler exists to handle this case.
I had the same problem, but I needed to compare multiple properties at the same time (class User with properties Name and Id).
I resolved this by adding a method returning an NSDictionary with the properties needed to the class:
- (NSDictionary *)itemProperties
{
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
[dict setObject:self.name forKey:#"name"];
[dict setObject:self.id forKey:#"id"];
return dict;
}
and then using valueForKey: as Kevin Ballard mentioned:
BOOL userSetsEqual = [[userSet1 valueForKey:#"itemProperties"]
isEqualToSet:[userSet2 valueForKey:#"itemProperties"]];
... where userSet1 and userSet2 were the NSSets that contained User objects.
You could just call valueForKey: on both sets and compare the results.
if ([[set1 valueForKey:#"name"] isEqualToSet:[set2 valueForKey:#"name"]]) {
// the sets match your criteria
}
Looking through the documentation, it seems that there is no way to really handle this special case of yours. You're going to have to write some custom code to handle this. Personally, I would recommend using -sortedArrayUsingDescriptors: and then comparing the arrays, but that's just me. You could also go enumerate through one set, then narrow down the other using -filteredSetUsingPredicate: and get its count.
Whichever method you use, consider the fact that its probably not going to be super efficient. This might be unavoidable, but there are probably ways to go about it that are better than others. Food for thought.

How can I remove the first element of an array in Objective C?

In Objective C, is there a one-liner or something small to remove (shorten by one) and return the first element of an array, regardless of its index?
I don't know of a method that returns the item removed, but you can do this using a combination of NSArray#objectAtIndex:0 and NSMutableArray#removeObjectAtIndex:0. I suppose you could introduce a new method category on NSMutableArray that implements a shift method.
That would be a poor thing to do.
Objective-C on the iPhone can actually use most of the performance perks of C.
If you look at some of my other posts, you'll see I'm ADAMANTLY against premature optimization, but when you are coding at the C level, there are just some things you don't do unnecessarilly.
Move memory
Duplicate structures
Allocate sparsely populated memory blocks
Inner loops
... (There are lots more, but my C-life is rusty and, as I said, I'm anti-optimization)
What you probably want is a well-implemented queue. Something that pre-allocates a large enough circular memory structure and then has two pointers that track the first and last bytes.
I'd be pretty surprised to hear that Objective-C didn't have a queue data structure.
Also, don't strive for the one-liners. All the stuff about terse code is overrated. If it makes more sense to call a method, so be it.
It's certainly too late to assist the original poster, but if you have a plain NSArray and not an NSMutableArray, this works well:
id myData = myArray.firstObject;
myArray = [myArray subarrayWithRange:NSMakeRange(1, myArray.count - 1)];
Cocoa array objects (NSArray/NSMutableArray) do not provide a one-line equivalent — you would have to read the object first, then remove it. The fact that these classes provide the methods -lastObject and -removeLastObject but not -firstObject and -removeFirstObject should be a reminder that removing from the front of an array is usually an inefficient operation, since the contents must be shifted (copied) one position forward. This is particular true for arrays in C, which are intrinsically tied with pointers.
If you're working with anything but primitive data types and/or very small arrays, you might want to consider that the behavior of "shifting off" the first element is indicative of a queue data structure. For details on how you might create a queue for objects, see this SO question. Personally, my opinion for that question is that a real queue class provides the cleanest programming idiom. You can even define your own method (perhaps as a category on NSMutableArray or another class) that does provide a one-liner to do what you want:
#interface NSMutableArray (QueueOneLiner)
- (id) removeAndReturnFirstObject; // Verbose, but clearer than "shift"
#end
#implementation NSMutableArray (QueueOneLiner)
- (id) removeAndReturnFirstObject {
id object = [[self objectAtIndex:0] retain];
[self removeObjectAtIndex:0];
return [object autorelease];
}
#end
However, by that point the solution will likely cause more overhead than it's worth, depending on the importance you place on simplicity versus performance of the code that uses it.
If you have an array obj *arr where obj is a class/typename and arr is the array, you can just say arr+1 to get the array without the first element.
Use this code,
[arrayName removeObjectAtIndex:0];
this may help you