有些情况下需要打乱一个数组的顺序,比如牌类游戏的洗牌。
如果是 Java 服务器,Java SDK 提供了一个 randomArray 的 API。但 iOS 并没有提供,Let's DIY。
主要思想是利用 iOS 提供的排序函数 sortUsingComparator:
,正常情况下的比较会返回 NSOrderedAscending = -1L, NSOrderedSame, NSOrderedDescending
,对应的整形值分别是 -1, 0, 1,如果我们随机返回这三个数呢?
NSMutableArray *array = [@[@"1", @"2", @"3", @"4", @"5", @"6", @"7", @"8", @"9"] mutableCopy];
[array sortUsingComparator:^NSComparisonResult(id _Nonnull obj1, id _Nonnull obj2) {
return (NSInteger)arc4random() % 3 - 1;
}];
这么做会不会有什么风险呢?比如在排序过程中,进行了校验,如果进行了校验,肯定是通不过,有可能导致死循环。
所以我们加上两个输出,来验证一下结果,并顺便一探 iOS SDK 为我们提供的排序算法是哪一类。
NSMutableArray *array = [@[@"1", @"2", @"3", @"4", @"5", @"6", @"7", @"8"] mutableCopy];
NSLog(@"%@, %p", array, array);
[array sortUsingComparator:^NSComparisonResult(id _Nonnull obj1, id _Nonnull obj2) {
NSInteger randomResult = (NSInteger)arc4random() % 3 - 1;
NSLog(@"%@, %@, %@", obj1, obj2, @(randomResult));
return randomResult;
}];
NSLog(@"%@, %p", array, array);
为了方便查看,我将 NSLog 输出的前一段信息去掉了,输出结果为:
1, 2
3, 4
2, 3
2, 4
5, 6
7, 8
7, 9
5, 8
6, 8
6, 7
3, 5
3, 8
4, 8
4, 6
4, 7
2, 7
2, 9
1, 9
(
5,
3,
8,
6,
4,
7,
2,
9,
1
)
第二次运行结果为:
1, 2
3, 4
2, 4
1, 4
1, 3
5, 6
7, 8
8, 9
7, 9
6, 7
6, 9
6, 8
5, 8
2, 7
2, 9
2, 6
2, 8
4, 8
4, 5
(
7,
9,
6,
2,
8,
5,
4,
1,
3
)
可以看出是随机排了序,并没有引起死循环或者其他问题。
那么使用的排序方式是哪一种呢?
尽管最后结尾的比较顺序不尽相同,但从前面几次还说可以看出一些端倪,首先是前4个进行比较,然后说后5个进行比较,所以应该是二分排序?
然而并不是,如果我们在排序过程中,输出这个数组,你会发现这个数组在排序过程中并没有发生变化。
或者找一个简单的无序数组,然后按正常的方式输出 obj1 obj2 以及正确的比较结果,然后手动跟着一步一步的排序,你会发现,按照这些根本没用办法正确排序。
所以我推测,在排序时,有另外的一个数据区,这个排序先通过比较取得相关的信息,并将信息存入这个数据区,最后根据信息来调整顺序。
如果你知道,欢迎在评论区回复。
Github
我封装了 OC 版本和 Swift 版本的随机数组分类
RandomArray_Swift
RandomArray_OC
如果你有更好的建议,欢迎在评论区回复。