Objective-C 练习题,题目来源 exercism.io,一共 50 题,见 GitHub

第二篇共 10 题。

(一)
(三)
(四)
(五)

# Raindrops

题目和测试用例见链接,下同。 Raindrops
Convert a number to a string, the contents of which depend on the number’s factors.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// Raindrops.h
#import <Foundation/Foundation.h>

@interface Raindrops : NSObject

@property (nonatomic, copy) NSString *sounds;

- (instancetype)initWithNumber:(NSInteger)number;

@end

// Raindrops.m
#import "Raindrops.h"

@implementation Raindrops

- (instancetype)initWithNumber:(NSInteger)number {
if (self = [super init]) {
NSString *sound = @"";
if (number % 3 == 0) {
sound = [sound stringByAppendingString:@"Pling"];
}
if (number % 5 == 0) {
sound = [sound stringByAppendingString:@"Plang"];
}
if (number % 7 == 0) {
sound = [sound stringByAppendingString:@"Plong"];
}
if (sound.length == 0) {
sound = [@(number) stringValue];
}
self.sounds = sound;
}
return self;
}

@end

# Grade School

Grade School
Given students’ names along with the grade that they are in, create a roster for the school

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
// GradeSchool.h
#import <Foundation/Foundation.h>

@interface GradeSchool : NSObject

- (void)addStudentWithName:(NSString *)name andGrade:(NSNumber *)grade;
- (NSDictionary *)db;
- (NSArray *)studentsInGrade:(NSNumber *)grade;
- (NSDictionary *)sort;

@end

// GradeSchool.m
#import "GradeSchool.h"

@implementation GradeSchool {
NSMutableDictionary *_kGrades;
}

- (instancetype)init {
if (self = [super init]) {
_kGrades = [NSMutableDictionary dictionary];
}
return self;
}

- (void)addStudentWithName:(NSString *)name andGrade:(NSNumber *)grade {
NSMutableArray *names = _kGrades[grade];
if (names) {
[names addObject:name];
} else {
_kGrades[grade] = [NSMutableArray arrayWithObject:name];
}
}

- (NSDictionary *)db {
return _kGrades;
}

- (NSArray *)studentsInGrade:(NSNumber *)grade {
return _kGrades[grade] ? _kGrades[grade] : @[];
}

- (NSDictionary *)sort {
for (NSMutableArray *array in [_kGrades allValues]) {
[array sortUsingComparator:^NSComparisonResult(NSString *obj1, NSString *obj2) {
return [obj1 compare:obj2];
}];
}
return _kGrades;
}

@end

# Etl

Etl
We are going to do the Transform step of an Extract-Transform-Load.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// Etl.h
#import <Foundation/Foundation.h>

@interface Etl : NSObject

+ (NSDictionary *)transform:(NSDictionary *)old;

@end

// Etl.m
#import "Etl.h"

@implementation Etl

+ (NSDictionary *)transform:(NSDictionary *)old {
NSMutableDictionary *results = [NSMutableDictionary dictionary];
for (NSNumber *key in [old allKeys]) {
for (NSString *letter in old[key]) {
results[[letter lowercaseString]] = key;
}
}
return results;
}

@end

# Isogram

Isogram
Determine if a word or phrase is an isogram.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// Isogram.h
#import <Foundation/Foundation.h>

@interface Isogram : NSObject

+ (BOOL)isIsogram:(NSString *)words;

@end

// Isogram.m
#import "Isogram.h"

@implementation Isogram

+ (BOOL)isIsogram:(NSString *)words {
NSString *newWords = [[[words lowercaseString]
stringByReplacingOccurrencesOfString:@" " withString:@""]
stringByReplacingOccurrencesOfString:@"-" withString:@""];
NSMutableArray *charsArray = [NSMutableArray array];
for (NSInteger i = 0; i < newWords.length; ++i) {
NSString *str = [newWords substringWithRange:NSMakeRange(i, 1)];
if ([charsArray containsObject:str]) {
return NO;
}
[charsArray addObject:str];
}
return YES;
}

@end

# Flatten Array

Flatten Array
Take a nested list and return a single list with all values except nil/null

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// FlattenArrayExample.h
#import <Foundation/Foundation.h>

@interface FlattenArrayExample : NSObject

+ (NSArray *)flattenArray:(NSArray *)array;

@end

// FlattenArrayExample.m
#import "FlattenArrayExample.h"

@implementation FlattenArrayExample

+ (NSArray *)flattenArray:(NSArray *)array {
NSMutableArray *flattenArray = [NSMutableArray array];
return [self recursive:flattenArray withInputArray:array];
}

+ (NSArray *)recursive:(NSMutableArray *)flattenArray withInputArray:(NSArray *)inputArray {
[inputArray enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
if ([obj isKindOfClass:[NSArray class]]) {
[self recursive:flattenArray withInputArray:obj];
} else if (![obj isKindOfClass:[NSNull class]]) {
[flattenArray addObject:obj];
}
}];
return flattenArray;
}

@end

# Prime Factors

Prime Factors
Compute the prime factors of a given natural number.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// PrimeFactors.h
#import <Foundation/Foundation.h>

@interface PrimeFactors : NSObject

+ (NSArray *)factorsForInteger:(NSInteger)number;

@end

// PrimeFactors.m
#import "PrimeFactors.h"

@implementation PrimeFactors

+ (NSArray *)factorsForInteger:(NSInteger)number {
NSMutableArray *result = [NSMutableArray array];
[self factors:result witnInput:number];
return result;
}

+ (void)factors:(NSMutableArray *)result witnInput:(NSInteger)number {
for (NSInteger i = 2; i <= number; ++i) {
if (number % i == 0) {
[result addObject:@(i)];
[self factors:result witnInput:number / i];
break;
}
}
}

@end

# Sublist

Sublist
Write a function to determine if a list is a sublist of another list.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// SublistExample.h
#import <Foundation/Foundation.h>

typedef NS_ENUM(NSUInteger, SublistKind) {
SublistKindEqual,
SublistKindUnequal,
SublistKindSublist,
SublistKindSuperlist,
};

@interface SublistExample : NSObject

+ (SublistKind)classifierForFirstList:(NSArray *)array andSecondList:(NSArray *)secondArray;

@end

// SublistExample.m
#import "SublistExample.h"

@implementation SublistExample

+ (SublistKind)classifierForFirstList:(NSArray *)array andSecondList:(NSArray *)secondArray {
if ([array isEqualToArray:secondArray]) {
return SublistKindEqual;
}
NSArray *largerArray = array.count > secondArray.count ? array : secondArray;
NSArray *smallerArray = largerArray == array ? secondArray : array;
for (NSInteger i = 0; i <= largerArray.count - smallerArray.count; ++i) {
NSArray *subArray = [largerArray subarrayWithRange:NSMakeRange(i, smallerArray.count)];
if ([smallerArray isEqualToArray:subArray]) {
if (smallerArray == array) {
return SublistKindSublist;
} else {
return SublistKindSuperlist;
}
}
}
return SublistKindUnequal;
}

@end

# Clock

Clock
Implement a clock that handles times without dates.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
// Clock.h
#import <Foundation/Foundation.h>

@interface Clock : NSObject

+ (instancetype)clockWithHours:(NSInteger)hours;
+ (instancetype)clockWithHours:(NSInteger)hours minutes:(NSInteger)minutes;
- (instancetype)addMinutes:(NSInteger)addMinutes;
- (instancetype)subtractMinutes:(NSInteger)subtractMinutes;

@end

// Clock.m
#import "Clock.h"

@interface Clock ()

@property (nonatomic, assign) NSInteger minutes;

@end

@implementation Clock

+ (instancetype)clockWithHours:(NSInteger)hours {
Clock *clock = [[self alloc] init];
clock.minutes = hours * 60;
return clock;
}

+ (instancetype)clockWithHours:(NSInteger)hours minutes:(NSInteger)minutes {
Clock *clock = [[self alloc] init];
clock.minutes = hours * 60 + minutes;
return clock;
}

- (instancetype)addMinutes:(NSInteger)addMinutes {
self.minutes += addMinutes;
return self;
}

- (instancetype)subtractMinutes:(NSInteger)subtractMinutes {
self.minutes -= subtractMinutes;
return self;
}

- (NSString *)description {
NSInteger hours = labs(self.minutes) / 60 % 24;
NSInteger minutes = labs(self.minutes) % 60;
if (self.minutes < 0) {
hours = 24 - hours - (minutes > 0 ? 1 : 0);
if (minutes > 0) {
minutes = 60 - minutes;
}
}
return [NSString stringWithFormat:@"%02ld:%02ld", (long)hours, (long)minutes];
}

- (BOOL)isEqual:(Clock *)object {
return [[self description] isEqualToString:[object description]];
}

@end

# Triangle

Triangle
Determine if a triangle is equilateral, isosceles, or scalene.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// Triangle.h
#import <Foundation/Foundation.h>

typedef NS_ENUM(NSUInteger, TriangleKind) {
TriangleKindEquilateral,
TriangleKindIsosceles,
TriangleKindScalene,
};

@interface Triangle : NSObject

+ (TriangleKind)kindForSides:(float)side1 :(float)side2 :(float)side3;

@end

// Triangle.m
#import "Triangle.h"

@implementation Triangle

+ (TriangleKind)kindForSides:(float)side1 :(float)side2 :(float)side3 {
NSAssert(side1 > 0, @"sides have to be of length > 0");
NSAssert(side2 > 0, @"sides have to be of length > 0");
NSAssert(side3 > 0, @"sides have to be of length > 0");
NSAssert(side1 + side2 > side3, @"not a triangle");
NSAssert(side1 + side3 > side2, @"not a triangle");
NSAssert(side2 + side3 > side1, @"not a triangle");
if (side1 == side2 && side2 == side3) {
return TriangleKindEquilateral;
} else if (side1 == side2 || side2 == side3 || side1 == side3) {
return TriangleKindIsosceles;
} else {
return TriangleKindScalene;
}
}

@end

# Robot Name

Robot Name
Manage robot factory settings.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
// Robot.h
#import <Foundation/Foundation.h>

@interface Robot : NSObject

- (NSString *)name;
- (void)reset;

@end

// Robot.m
#import "Robot.h"

static NSMutableArray *names;
static NSArray *letters;

@interface Robot ()

@property (nonatomic, copy) NSString *robotName;

@end

@implementation Robot

- (NSString *)name {
if (self.robotName) {
return self.robotName;
}

if (!letters) {
letters = @[ @"A", @"B",@"C", @"D", @"E", @"F", @"G", @"H", @"I", @"J", @"K", @"L", @"M", @"N", @"O", @"P", @"Q", @"R", @"S", @"T", @"U", @"V", @"W", @"X", @"Y", @"Z" ];
}
if (!names) {
names = [NSMutableArray array];
}

NSString *name;
do {
name = [NSString stringWithFormat:@"%@%@%03u", letters[arc4random() % 26], letters[arc4random() % 26], arc4random() % 1000];
} while ([names containsObject:name]);
[names addObject:name];
self.robotName = name;
return name;
}

- (void)reset {
self.robotName = nil;
}

@end