【问题标题】:Alternative to NSCountedSet in Objective-C to keep order在 Objective-C 中替代 NSCountedSet 以保持秩序
【发布时间】: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


【解决方案1】:

这就是我最后的结果。

    #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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-04-12
    • 2013-07-22
    • 2017-12-23
    • 1970-01-01
    • 1970-01-01
    • 2018-04-17
    • 2017-05-29
    • 1970-01-01
    相关资源
    最近更新 更多