my array has the following:
{
"4eb57e72c7e24c014f000000" : {
"_id" : {
"$id" : "4eb57e72c7e24c014f000000"
},
"author" : "tim",
"comments" : [],
"created": {
"sec" : 1320517234,
"used" : 856000
},
"picture" : "http://someurl.com",
"text" : "this is a test",
"title" : "test",
"type" : ["test"]
}
I want to sort by created (sec value)
this is what I have....I just do not know how sortedArrayUsingFunction works. I mean what am I comparing in the compare function??
jokesArray = [unSortedContentArray sortedArrayUsingFunction:Sort_Created_Comparer context:self];
NSInteger Sort_Created_Comparer(id num1, id num2, void *context)
{
int v1 = [num1 getSecFromJSONValue];
int v2 = [num2 getSecFromJSONValue];
if (v1 < v2)
return NSOrderedAscending;
else if (v1 > v2)
return NSOrderedDescending;
else
return NSOrderedSame;
}
num1 and num2 are 2 elements of your array and context is an object that you can pass in to your function to help you with the sort.
Your function will be called many times on the array and the result of the sort will be returned to you in a new array.
Is that what you are wondering?
The comparison function is called to compare two values at a time from your NSArray. This is how the sorting is done.
The comparison function is your way of telling the sort algorithm how you want your objects ordered. Without it, it has no way of knowing what the final order should be.
In your example code the argument names num1 and num2 are very misleading. They would be more accurately named object1 and object2. If object1 should come before object2 then return NSOrderedAscending. If it should come after then NSOrderedDescending otherwise return NSOrderedSame.
To illustrate, here is an example that sorts hypothetical Person objects by age (lowest to highest).
NSInteger youngest_first(id object1, id object2, void *context) {
if (object1.age < object2.age) {
return NSOrderedAscending;
}
else if (object1.age > object2.age) {
return NSOrderedDescending;
}
else {
return NSOrderedSame;
}
}
Notice that I didn't even use the context parameter as my objects themselves had sufficient information to determine the order.
If I instead want them to be sorted by descending height then I could pass the following:
NSInteger tallest_first(id object1, id object2, void *context) {
if (object1.height > object2.height) {
return NSOrderedAscending;
}
else if (object1.height < object2.height) {
return NSOrderedDescending;
}
else {
return NSOrderedSame;
}
}
One thing that is very important is that your function should return a consistent result if the arguments are passed in the other order. For example if tallest_first(adam, joe, NULL) returns NSOrderedDescending then tallest_first(joe, adam, NULL) should return NSOrderedAscending. If not your comparison function contradicts itself.
Related
I have following code which is working in Objective-C:
NSScanner *scanner ;
for(int i = 0; i < [expression count]; i = i + 2)
{
scanner = [NSScanner scannerWithString:[expression objectAtIndex:i]];
BOOL isNumeric = [scanner scanInteger:NULL] && [scanner isAtEnd];
if(!isNumeric)
return false;
}
return true;
I need equivalent code in Swift 4. I have tried different things but couldn't work it out. The requirement is to check whether the elements of array are number or not.
To check if an object is a number (Int in your case), you could do two things:
Type check via is or as?
This only checks the type and not the content
let isNumberType = "1" is Int
print(isNumberType) //false because "1" is of type String
Creating an Int via it's initializer
This returns an Int? because it can fail so further check != nil
let something = "1"
let isNumber = Int(something) != nil
print(isNumber) //true because "1" can be made into an Int
NOTE: As per your example, you're checking only even elements, hence we will use stride(from:to:by:)
Solution #1:
Assuming you have an array of Strings, we can use the Int initializer to check if the string element can be a number, like so:
func check(expression: [String]) -> Bool {
for idx in stride(from: 0, to: expression.count, by: 2) {
let isNumeric = Int(expression[idx]) != nil
if isNumeric == false {
return false
}
}
return true
}
check(expression: ["1", "A", "2", "B", "3", "C"]) //true
check(expression: ["1", "A", "2", "B", "E", "C"]) //false
Solution #2:
Assuming your array is of type [Any] and you want to type check the alternate elements to be Int then use is, like so:
func check(expression: [Any]) -> Bool {
for idx in stride(from: 0, to: expression.count, by: 2) {
let isNumeric = expression[idx] is Int
if isNumeric == false {
return false
}
}
return true
}
check(expression: [1, "A", 2, "B", 3, "C"]) //true
check(expression: [1, "A", 2, "B", "3", "C"]) //false
The thing with [Any] is that it's elements can't be fed directly to the Int's initializer without bringing it into an acceptable type.
So in this example, for simplicity sake, we are just checking if the object is exactly of type Int or not.
Therefore, I doubt this one suits your requirement.
Try this:
var str = "1234456";
let scanner = Scanner(string: str);
let isNumeric = scanner.scanInt(nil) && scanner.isAtEnd
if !isNumeric {
print("not numeric")
} else {
print("is numeric")
}
Overall if you just want to check the given string is an parsable Integer, I recommend you try :
var expressions = ["1234456","abcd"];
for str in expressions {
if let isNumeric = Int(str) {
print("is numeric")
} else {
print("not numeric")
}
}
I have an array of PFObjects. I'd like to search if the "Type" contains "Sushi". The filter alters the array. How can I preform this search without altering the array?
func startCheckOptions(objects: [AnyObject]) {
let filteredArray = objects.filter() {
if let type = ($0 as PFObject)["Type"] as String {
//if "type" contains "sushi", then do something instead of alter array
return type.rangeOfString("Sushi") != nil
} else {
return false
}
}
}
You can use the contains function:
func startCheckOptions(objects: [AnyObject]) -> Bool {
return contains(objects as [PFObject]) { (object) -> Bool in
if let type = object["Type"] as? String {
return type.rangeOfString("Sushi") != nil
}
else {
return false
}
}
}
if startCheckOptions(objects) {
println("yes")
}
else {
println("no")
}
This has the advantage of not building a new array containing the matching objects and stopping on the first match.
In this case you'd be better off protecting the objects cast (or really handling one time somewhere else) by casting it to [PFObject] ASAP. Leaving AnyObject references floating around can only lead to confusion and heartache.
filter() does not alter an array, but it returns a new array. What you have above is correct. objects will be the original array, and filteredArray will be the new array consistent of objects where "type" is "sushi".
I saw several questions on this problem, but none about iOS.
I have two enums like following :
// My first enum eColor
typedef enum
{
eColorRed = 1,
eColorGreen,
eColorBlue
} eColor;
// My second enum eShape
typedef enum
{
eShapeCircle = 1,
eShapeSquare,
eRectangle
} eShape;
I would like to have a method which accept both of these enums like this :
+ (NSString*) toStr:(bothEnum)e
{
NSString *result = nil;
if (bothEnum == eColor)
{
switch(e) {
case eColorRed:
result = #"red";
break;
case eColorGreen:
result = #"green";
break;
case eColorBlue:
result = #"blue";
break;
default:
result = #"unknown";
}
}
else if (bothEnum == eShape)
{
switch (e) {
case eShapeCircle:
result = #"circle";
break;
case eShapeSquare:
result = #"square";
break;
case eShapeRectangle:
result = #"rectangle";
break;
default:
result = #"unknown";
}
}
return result;
}
Is a thing like this possible ?
I don't want to have methods like colorToStr:, shapeToStr:, etc. My wish is to have only one method called toStr:, as above...
Enums are just constants and at run time they are just numbers. So your method doesn't know what is eColorRed, it knows it as 1, and your only option is to pass additional parameter, telling your method wether 1 passed in first argument is eColorRed or eShapeCircle. It can be just a string, like:
+ (NSString*) toStr:(NSUInteger)e fromEnumType:(NSString*)type
{
if([type isEqualToString:#"eColor"])
{
switch(e)
...
}
else if([type isEqualToString:#"eShape"])
{
switch(e)
...
}
}
You may try this approach: You make the second enum to start indexing from the last index of the first enum, then you just use single witch in your method. Remember enum type is just an int type indeed.
// My first enum
typedef enum
{
eColorRed = 1,
eColorGreen,
eColorBlue,
eColorLastIndex
} eColor;
// My second enum
typedef enum
{
eShapeCircle = eColorLastIndex,
eShapeSquare,
eShapeRectangle,
} eShape;
typedef int eTypes;
+(NSString*)toStr:(eTypes)e
{
NSString *result = nil;
switch(e) {
case eColorRed:
result = #"red";
break;
case eColorGreen:
result = #"green";
break;
case eColorBlue:
result = #"blue";
break;
case eShapeCircle:
result = #"circle";
break;
case eShapeSquare:
result = #"square";
break;
case eShapeRectangle:
result = #"rectangle";
break;
default:
result = #"unknown";
break;
}
return result;
}
Instead eGraphics you may use just int or eColorShape, whatever.
Update for 64-bit Change:
According to apple docs about 64-bit changes,
Enumerations Are Also Typed : In the LLVM compiler, enumerated types can
define the size of the enumeration. This means that some enumerated
types may also have a size that is larger than you expect. The
solution, as in all the other cases, is to make no assumptions about a
data type’s size. Instead, assign any enumerated values to a variable
with the proper data type
So you have to create enumeration with type as below syntax if you support for 64-bit.
typedef enum eColor : NSUInteger {
eColorRed = 1,
eColorGreen,
eColorBlue
} eColor;
then go with #user2260054's answer, otherwise, it will lead with below warning in 64-bit environment.
Otherwise, it will lead to warning as Implicit conversion loses integer precision: 'NSUInteger' (aka 'unsigned long') to eColor
This is not good for design point of view. Cohesion is broken over here. While programming OOP concept must be implemented for reuse of code and decoupling the objects as well.
Say I have 2 NSDictionaries that I don't know beforehand like:
NSDictionary *dictA = #{ #"key1" : #1,
#"key2" : #2 };
NSDictionary *dictB = #{ #"key1" : #"a string" };
I want to find the first match between the keys of dictB and the keys or values of dictA. Each key of dictB will either be a NSNumber or a string. If it's a number, try to find a match from the values of dictA. If it's a string, try to find a match from the keys of dictA.
Using for loops, it would looks something like this:
id match;
for (id key in dictA ) {
for (id _key in dictB {
if ( [_key is kindOfClass:NSNumber.class] && _key == dictA[key] ) {
match = _key
goto outer;
}
else if ( [_key is kindOfClass:NSString.class] && [_key isEqualToString:key] ) {
match = _key
goto outer;
}
}
};
outer:;
NSString *message = match ? #"A match was found" : #"No match was found";
NSLog(message);
How could I rewrite this with ReactiveCocoa using RACSequence and RACStream methods so it looks something like:
// shortened pseudo code:
// id match = [dictA.rac_sequence compare with dictB.rac_sequence using block and return first match];
You basically would like to create the cartesian product of the dictionaries and make a selection on it. There is no default operator in ReactiveCocoa that I know of that would do this for you. (In LINQ there are operators for this.) In RAC the simplest solution is to use the scanWithStart:combine: method to implement this operation. Once the cartesian is ready, the filter: and take:1 operations will produce the sequence of your choice.
NSDictionary *adic = #{#"aa":#"vb", #"ab": #"va"};
NSDictionary *bdic = #{#"ba": #"va", #"bb":#"vb"};;
RACSequence *aseq = adic.rac_keySequence;
RACSequence *bseq = bdic.rac_keySequence;
RACSequence *cartesian = [[aseq scanWithStart:nil combine:^id(id running, id next_a) {
return [bseq scanWithStart:nil combine:^id(id running, id next_b) {
return RACTuplePack(next_a, next_b);
}];
}] flatten];
RACSequence *filteredCartesian = [cartesian filter:^BOOL(RACTuple *value) {
RACTupleUnpack(NSString *key_a, NSString *key_b) = value;
// business logic with keys
return false;
}];
RACSequence *firstMatch = [filteredCartesian take:1];
I am an Objective C noob and need a bit of help.
I need to pass a function 2 integers A and B.
The called function then checks if A > B, A = B or A < B and passes back a string.
If A > B then it must pass back "HOT"
If A = B then it must pass back "MEDIUM"
If A < B then it must pass back "COLD"
Also how do I call this function from within another function?
Any help would be appreciated.
Thanks.
- (NSString *)stringForTemperature:(int)temperature base:(int)base {
if (temperature > base) {
return #"HOT";
} else if (temperature < base) {
return #"COLD";
} else {
return #"MEDIUM";
}
}
- (void) otherFunction {
NSString *temperatureString = [self stringForTemperature:A base:B];
}
-(NSString*) myMethod: (int) one two:(int)two {
if( one > two ) return #"HOT";
if( one == two ) return #"MEDIUM";
return #"COLD";
}
You can then call this like such:
[myObject myMethod:10 two:30]; //returns "COLD"