Two arrays with specific object at same index - objective-c

How do I check if two arrays have one specific object that is not related at one common index for both arrays in Objective-C?
if ([[Array1 objectAtIndex:SameIndex] containsObject:String1] && [[Array2 objectAtIndex:SameIndex] containsObject:String2]) {
}
When I think of it, I may have to use a loop instead of an if statement.
Any help would be greatly appreciated.

The isEqual method allows you to compare two objects. You could do something similar to:
NSArray *array1 = #[[NSNumber numberWithInteger:10],
[NSNumber numberWithInteger:20],
[NSNumber numberWithInteger:30]];
NSArray *array2 = #[[NSNumber numberWithInteger:60],
[NSNumber numberWithInteger:70],
[NSNumber numberWithInteger:80]];
NSNumber *object1 = [NSNumber numberWithInteger:20];
NSNumber *object2 = [NSNumber numberWithInteger:70];
NSUInteger sameIndex = 1;
if ([[array1 objectAtIndex:sameIndex] isEqual:object1] && [[array2 objectAtIndex:sameIndex] isEqual:object2]) {
// Do something
NSLog(#"Validation passed!");
}
That will compare the object stored at index sameIndex in array1 and array2 with object1 and object2 respectively.
EDIT: I changed my code snippet into a working example for you to better understand.

You can use a few method on NSArray to find the object, for example:
[Aarray1 indexOfObject:...]
[Aarray1 indexOfObjectIdenticalTo:...]
[Aarray1 indexOfObjectPassingTest:...]
After that just make sure that you have an index and if index exists you know that there is an object. You have to just slightly amended code from your question.

Related

Pass C array to a objective C method

I want to make an array of integers with as little code as possible and pass that array to an objective C method.
I tried the below. sequence starts out as an array and is passed to setLights: but when sequence is looked at in the method (via breakpoint) it is no longer an array.
*EDIT: I didnt want to use an NSArray because an NSArray of integers is so verbose:
Using NSArray:
NSArray *sequence = [[NSArray alloc] initWithObjects: [NSNumber numberWithInt:0], [NSNumber numberWithInt:1], [NSNumber numberWithInt:2], [NSNumber numberWithInt:3], [NSNumber numberWithInt:4],[NSNumber numberWithInt:5],nil];
Using C array:
int sequence[6] = {0,1,2,3,4,5};
What am I doing wrong?
- (IBAction)testLights:(id)sender {
int sequence[6] = {0,1,2,3,4,5};
//int *sequence[0][1][2][3][4][5]; //also tried this
[self setLights:sequence];
}
- (void)setLights:(int *)sequence {
UIImageView *light=[lgtArray objectAtIndex: sequence[0]];
light.alpha = 0;
[UIView animateWithDuration:0.3f
animations:^{
light.alpha = 1;
}completion:nil
];
}
Use this syntax to pass the array:
- (void)setLights:(int[] )sequence
You are running into a bizarre feature of C that has propagated through its variants: the [mostly] equivalence of pointers and arrays.
if you do
int *sequence ;
then you can do
sequence [4] ;
or
*(sequence + 4)
Arrays and points are mostly interchangeable. Arrays in C variants are merely data allocation. Your definition of
- (void)setLights:(int *)sequence
conveys no information array information. You can still access sequence as though it is an array. setLights simply has no intrinsic information as to how many elements sequence has allocated to it.
The problem here is that your usage of the array in setLights needs to match how you have allotted the data.
If you did
sequence [100] = 10 ;
it would be syntactically correct but likely to create an error.
Is verbose only if you want. Use literals instead:
NSArray *sequence = #[#0, #1, #2, #3, #4, #5];
And access to the value like this:
UIImageView *light = lgtArray[[sequence[0] intValue]]];

Get list of Values for an NSArray of NSDictionary

I've got the following NSArray :
NSArray myArray = #[#{#300:#"5 min"},
#{#900:#"15 min"},
#{#1800:#"30 min"},
#{#3600:#"1 hour"}];
I want the list of value of my dictionaries :
#[#"5 min",#"15 min",#"30 min",#"1 hour"]
And the list of key of my dictionaries :
#[#300, #900, #1800, #3600]
What is the best way to do that ? I was thinking about predicate, but I don't know how to use it ?
Without some code to show how you'd want to go about this it is difficult to be sure exactly what you are after, and there is a bit of confusion in the question.
First, a predicate is exactly that - a statement that can be proven true or false. Predicates are hence used in logic expressions, including those employed implicitly in database queries - such as Core Data.
That is not what you want, if I read your question correctly. What you want is to reduce the complexity of your data model, removing some excess (one would hope) information in the process. A sort of flattening of an array of dictionaries.
Fair enough.
I can also see how the confusion with predicates came about - they are most often constructed using Key-Value Coding. KVC, as it is also known, is a very powerful technique that can accomplish what you are after. It just does not have much to do with a logic statement.
Having cleared that up, with KVC you can do what you want, and with minimal fuss. It goes like this:
NSArray *values = [myArray valueForKeyPath: #"#unionOfArrays.#allValues"];
NSArray *keys = [myArray valueForKeyPath: #"#unionOfArrays.#allKeys"];
A brief explanation might be in order:
The results that we want are
All the values (or keys) of each dictionary, obtaining an array of arrays of values (or keys)
Then we want to flatten these arrays into a single array.
To obtain all values (or keys) from a dictionary using KVC, the special key is #allValues or #allKeys, respectively.
The #unionOfArrays operator makes a union of the arrays obtained from the expression that follows it, i.e., flattens it into the array you wanted.
The price you pay for this coding simplicity is that you have to use KVC key paths with collection operators, which are just strings in your code. You therefore lose any help from the compiler with syntax and it doesn't check that the keys you enter exist in the objects. Similarly, the debugger and error messages are unhelpful if you mistype or use the wrong operator, for instance.
You can use dictionary property allValues to get all values of dictionary.
Try this code in your case
NSArray *myArray = #[#{#300:#"5 min"},
#{#900:#"15 min"},
#{#1800:#"30 min"},
#{#3600:#"1 hour"}];
NSMutableArray *arr = [NSMutableArray array];
for (NSDictionary *dict in myArray) {
[arr addObject:[[dict allValues] objectAtIndex:0]];
}
NSLog(#"%#",arr);
Note : Make sure you have only one value in each dictionary.
it will return
[
5 min,
15 min,
30 min,
1 hour
]
#johnyu's answers is technically correct, but I don't see any reason to include the secondary loop, especially if the data structure will remain the same.
NSArray *myArray = #[#{#300:#"5 min"},
#{#900:#"15 min"},
#{#1800:#"30 min"},
#{#3600:#"1 hour"}];
NSMutableArray *arrayOfValues = [NSMutableArray new];
NSMutableArray *arrayOfKeys = [NSMutableArray new];
for (NSDictionary *dictionary in myArray) {
[arrayOfValues addObject:dictionary.allValues[0]];
[arrayOfKeys addObject:dictionary.allKeys[0]];
}
NSLog(#"%#",arrayOfKeys);
NSLog(#"%#",arrayOfValues);
Try this:
NSArray *myArray = #[#{#300:#"5 min"},
#{#900:#"15 min"},
#{#1800:#"30 min"},
#{#3600:#"1 hour"}];
NSMutableArray *keyArray = [[NSMutableArray alloc] init];
NSMutableArray *valueArray = [[NSMutableArray alloc] init];
for (NSDictionary *dictionary in myArray) {
for (NSString *key in dictionary) {
[keyArray addObject:key];
[valueArray addObject:[dictionary objectForKey:key]];
}
}

How to implement a for-in loop in Objective-C from the end of collection not from beginning?

I' m trying to iterate NSDictionary via the for in loop. But I want it to begin iteration from the end of this collection to its beginning. How can I implement this reversion?
NSDictionary is an unordered data structure. There is no concept of forward iteration, or backward iteration.
When you call NSDictionary in a foreach loop, you are iterating over an unordered list of keys. When Iterating an unordered list, the order is undefined, and thus so is reversing the order. It's akin to scattering a deck of cards on the floor, then asking someone to reverse the order.
Assuming there is some order hierarchy to your keys (numeric, alphabetical, etc), You can instead get the key collection, and sort it into a particular order, and then iterate the key collection, or reverse iterate that. However if this is an operation you are doing frequently, then I suspect that NSDictionary is not the best choice for a datastructure for your problem.
Mmm... the problem is that NSDictionary are unordered by nature.
So, a possible solution is make an NSArray with the keys, reverse that array with "reverseObjectEnumerator" and then make a loop over the array and use the keys on dictionary.
Something like this:
NSDictionary *_dict = [NSDictionary dictionaryWithObjectsAndKeys:
#"firstValue",#"firstKey",
#"secondValue",#"secondKey",
#"thirdValue",#"thirdKey",
nil];
NSArray *keysNormal = [_dict allKeys];
NSArray *keysReversed = [[[_dict allKeys] reverseObjectEnumerator] allObjects];
for(NSString *str in keysNormal)
{
NSLog(#"%#", [_dict objectForKey:str]);
}
for(NSString *str in keysReversed)
{
NSLog(#"%#", [_dict objectForKey:str]);
}
The log is:
thirdValue
secondValue
firstValue
firstValue
secondValue
thirdValue
NSArray * a = #[#"a",#"b",#"c"];
NSArray * b = [[a reverseObjectEnumerator] allObjects];
for (NSString * obj in b) {
NSLog(#"%#",obj);
}
Print c,b,a.
Try to reverse the keys of your dictionary like this:
NSArray * key = [[[dict allKeys] reverseObjectEnumerator] allObjects];

How to efficiently access large objects in Obj-C using objectForKey and objectAtIndex?

If I have a large NSDirectory typically from a parsed JSON-object I can access this object with code like so:
[[[[[obj objectForKey:#"root"] objectForKey:#"key1"] objectAtIndex:idx] objectForKey:#"key2"] objectAtIndex:idz];
The line might be a lot longer than this.
Can I optimize this code in any way? At least make it easier to read?
This line will also generate a runtime-error if the object does not correspond, what is the most efficient way to avoid that?
If you were using -objectForKey: for everything you could use -valueForKeyPath:, as in
[obj valueForKeyPath:#"key1.key2.key3.key4"]
However, this doesn't work when you need to use -objectAtIndex:. I don't think there's any good solution for you. -valueForKeyPath: also wouldn't solve the problem of the runtime errors.
If you truly want a simple way to do this you could write your own version of -valueForKeyPath: (call it something else) that provides a syntax for specifying an -objectAtIndex: instead of a key, and that does the appropriate dynamic checks to ensure the object actually responds to the method in question.
If you want easier to read code you can split the line into several lines like this
MyClass *rootObject = [obj objectForKey:#"root"];
MyClass *key1Object = [rootObject objectForKey:#"key1"];
MyClass *myObject = [key1Object objectAtIndex:idx];
...
and so forth.
I think, you can create some array, that will contain full "path" to your object. The only thing, you need to store your indexes somehow, maybe in NSNumber, in this case you cannot use NSNumber objects as keys in your dictionaries. Then create a method, that will return needed object for this given "path". smth like
NSMutableArray* basePath = [NSMutableArray arrayWithObjects: #"first", [NSNumber numberWithInt:index], nil];
id object = [self objectForPath:basePath inContainer:container];
- (id) objectForPath:(NSMutableArray*)basePath inContainer:(id)container
{
id result = nil;
id pathComponent = [basePath objectAtIndex: 0];
[basePath removeObjectAtIndex: 0];
// check if it is a number with int index
if( [pathComponent isKindOfClass:[NSNumber class]] )
{
result = [container objectAtIndex: [pathComponent intValue]];
}
else
{
result = [container objectForKey: pathComponent];
}
assert( result != nil );
// check if it is need to continue searching object
if( [basePath count] > 0 )
{
return [self objectForPath:basePath inContainer: result];
}
else
{
return result;
}
}
this is just an idea, but I hope you understand what I mean. And as Kevin mentioned above, if you don't have indexes, you can use key-value coding.
Don't know if it can suit you, but you could also give a try to blocks, I always find them very convenient. At least they made code much more readable.
NSArray *filter = [NSArray arrayWithObjects:#"pathToFind", #"pathToFind2",nil];
NSPredicate *filterBlock = [NSPredicate predicateWithBlock: ^BOOL(id obj, NSDictionary *bind){
NSArray *root = (NSArray*)obj;
// cycle the array and found what you need.
// eventually implementing some sort of exit strategy
}];
[rootObject filteredArrayUsingPredicate:filterBlock];

How does one populate an NSMutable array of NSMutableSets?

I am using this code in a loop to populate an NSMutable Array of NSMutableSets (of NSString objects). The index of the NSSet is based on the length of the word.
// if set of this length not initialized yet, initialize set.
wordIndex = [NSString stringWithFormat:#"%d", currentWordLength];
if ([myWordArray objectForKey:wordIndex] == nil)
[myWordArray setObject:[[NSMutableSet alloc] initWithObjects:currentWord, nil] forKey:wordIndex];
else
[[myWordArray objectForKey:wordIndex] addObject:currentWord];
The final intention is to split up an array of words into an array of sets of words grouped by their lengths.
However, I see that [myWordArray count] is 0 after this. Why?
You are confusing the methods of NSMutableDictionary and NSMutableArray: In Objective-C arrays do not have keys but have indexes. If you change the class for myWordArray to NSMutableDicitionary it should work.
Try this, it looks very much like your logic, but (1) it uses NSNumbers as keys, which makes a little more sense, (2) handles the missing set condition more simply, but just adding the set, and (3) breaks up the source lines somewhat for easier debugging...
NSArray *inputStrings = // however these are initialized goes here
NSMutableDictionary *result = [NSMutableDictionary dictionary];
for (NSString *currentString in inputStrings) {
NSInteger currentWordLength = currentString.length;
wordIndex = [NSNumber numberWithInt:currentWordLength];
NSMutableSet *wordSet = [result objectForKey:wordIndex];
if (!wordSet) {
wordSet = [NSMutableSet set];
[result setObject:wordSet forKey:wordIndex];
}
[wordSet addObject:currentWord];
}
If you still have an empty dictionary after running this, it might be simpler to watch what's happening by stepping through it.