【发布时间】:2016-07-06 18:45:18
【问题描述】:
下面的代码可以满足我的需要,除非它事后没有订购。(请不要告诉我它,因为 NSSet 是无序的,我知道。)这也不是一个重复的 SO 问题,我已经用过阅读所有“类似”问题超过 40 分钟,但它们并没有解决问题。
我正在尝试获取“事件”在给定时间段内发生的次数的“每小时”、“每天”、“每月”视图,在图表的 x 轴上标记该时间或日期,并标记它在 y 轴上发生的次数。它可以通过简单地通过升序使用下面的 dictArray 来正常工作,具体取决于我如何格式化要显示的字符串。这就是问题所在。对于每小时视图,我正在格式化“datesForEvent”数组中的字符串,如下所示 [7am, 7am, 7am, 8am, 8am, 11am, 11am, 1pm, 1pm, 3pm, 3pm] 所以当我将其排序回NSCountedSet 它将像这样在我的图表的 x 轴上显示它,即下午 1 点、下午 3 点、上午 7 点、上午 8 点、上午 11 点。显然不好。如果我将格式化的字符串作为每日视图放入“datesForEvent”数组中,如下所示 [sun, sun, sun, mon, mon, tue, wed, wed, wed, wed, thu, thu, fri, fri fri, fri]它将在 x 轴 fri、mon、sat、sun、thu、tue、wed 上像这样排序。同样的事情发生在月视图“Jul”将出现在“Jun”之前。
这完全有道理,但我不知道如何解决这个问题。这个问题绝对是由我在计算字符串之前如何格式化字符串引起的。但是,在计数之后格式化字符串会抛出给定时间段内发生的次数,因为日期格式对于所有事件的长度都是相同的,因此它将所有这些事件作为单次出现而不是作为分组事件,因为它们的时间精确到毫秒。换句话说,任何事件都不会有重复的时间,这也不好。我在 Apple 文档中遇到了日期格式、日期组件、日期样式等问题,但无济于事。我目前正在阅读谓词指南,同时希望获得任何类型的帮助。如果朝着正确的方向推进,将不胜感激。
以下是有问题的代码。具有讽刺意味的是,代码没有错误,因为它正在做我要求它做的事情。我需要 NSCountedSet 没有无序部分的功能。
NSCountedSet *countedSet = [[NSCountedSet alloc] initWithArray:self.datesForEvent];
NSMutableArray *groupedArray = [NSMutableArray array];
[countedSet enumerateObjectsUsingBlock:^(id obj, BOOL *stop) {
[groupedArray addObject:@{@"dates": obj,
@"count": @([countedSet countForObject:obj])}];
}];
//This sorting will sort alphabetically so its not good.
NSArray *orderedArray = [[NSArray alloc]initWithArray:[groupedArray sortedArrayUsingDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:@"dates" ascending:YES]]]];
这是对来自@CRD 的评论排序的更新。我从其他工作中快速休息了一下,想出了这个解决方案,以正确的顺序计算日期,这与不保持顺序的 NSOrderedSet 解决方案不同。但是,由于没有更好的词,我希望您对它的健壮性或优雅性提出意见。我觉得在数组末尾粘贴 [NSNull null] 有点笨拙?
#import "ViewController.h"
@interface ViewController ()
@property (nonatomic, strong) NSArray *baseArray;
@property (nonatomic, strong) NSMutableArray *datesArray;
@property (nonatomic, strong) NSMutableArray *countArray;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
//Base Array of counts should be - 07/1 (4), 7/2 (3), 7/3 (2), 7/4 (1)
self.baseArray = @[@"07/01/16",@"07/01/16",@"07/01/16",@"07/01/16",
@"07/02/16",@"07/02/16",@"07/02/16",
@"07/03/16",@"07/03/16",
@"07/04/16"];
self.datesArray = [[NSMutableArray alloc]init];
[self.datesArray addObjectsFromArray:self.baseArray];
[self.datesArray addObject:[NSNull null]];
self.countArray = [[NSMutableArray alloc]init];
int marker = 0;
int counter = 0;
//For loop for count of elements
for (int i = 0; i < self.datesArray.count; i++) {
if (self.datesArray[marker] == self.datesArray[i]) {
counter++;
NSLog(@"MDate %@ Index %@ Counter: %d Marker: %d", self.datesArray[marker], self.datesArray[i], counter, marker);
} else if (self.datesArray[marker] != self.datesArray[i]){
[self.countArray addObject:[NSNumber numberWithInt:counter]];
NSLog(@"Count is: %d", counter);
marker = i;
--i;
counter = 0;
}
}
NSLog(@"Count Array is: %@", self.countArray);
}
@end
【问题讨论】:
-
只需使用两个结构,一个数组来保持顺序,一个计数集来保持计数。
-
您没有展示如何“将其从
NSCountedSet中排序出来”,但是有很多方法可以使用排序函数(方法、块)进行排序,您可以提供一种在“pm”(主键)之前用“am”对时间进行排序,在较高的数字(辅助键)之前对较低的数字进行排序。或者使用 24 小时制格式化您的时间,并且仅在显示/图表中将它们转换为 12 小时。 HTH -
@CRD 有趣而简单的想法。我仍然会坚持按月排序,但这是一个好的开始。明天我会试一试,看看它会把我引向何方。
-
@Sulthan 好主意。实际上,我在显示之前将计数和订单输入到两个单独的结构中,因此我可以将计数集输入到另一个结构中。虽然我不确定它将如何保持计数顺序?我看到日期数组将如何被保留,但仍然看不到计数将如何保持不变,日期在一个数组中,而计数在另一个数组中?
-
为什么不直接编写代码来完成任务,而不是尝试从集合和排序中构建解决方案?如图所示,您的
datesForEvent数组已经按顺序排列,按顺序循环并减少为一对数组(日期、计数)并不难。如果datesForEvent没有被订购,那么它不会更难,例如循环可以使用插入排序并在碰撞时增加计数。
标签: ios objective-c nsarray nscountedset