【问题标题】:Objective-C Split an array into two separate arrays based on even/odd indexesObjective-C 根据偶数/奇数索引将数组拆分为两个单独的数组
【发布时间】:2015-01-28 07:08:10
【问题描述】:

我有一个数组,NSMutableArray *stringArray,看起来像这样

stringArray = 

[0]String1
[1]String2
[2]String3
[3]String4
[4]String5
[5]String6

如何根据偶数/奇数索引将此数组拆分为两个数组?

例子:

NSMutableArray *oddArray = ([1], [3], [5]);

NSMutableArray *evenArray = ([0], [2], [4]);

提前致谢!

【问题讨论】:

    标签: objective-c arrays nsmutablearray


    【解决方案1】:

    创建两个可变数组,在源数组上使用enumerateObjectsWithBlock: 并检查idx % 2 将其放入第一个或第二个数组

    使用三元运算符:

    NSArray *array = @[@1,@2,@3,@4,@5,@6,@7,@8,@9,@10,@11,@12];
    NSMutableArray *even = [@[] mutableCopy];
    NSMutableArray *odd = [@[] mutableCopy];
    [array enumerateObjectsUsingBlock:^(id object, NSUInteger idx, BOOL *stop) {
        NSMutableArray *evenOrOdd = (idx % 2) ? even : odd;
        [evenOrOdd addObject:object];
    }];
    

    如果你喜欢超级紧凑的代码,你可以使用三元运算符

    [((idx % 2) ? even : odd) addObject:object];
    

    如果要将数组拆分为N个数组,可以这样做

    NSArray *array = @[@1,@2,@3,@4,@5,@6,@7,@8,@9,@10,@11,@12];
    
    NSArray *resultArrays = @[[@[] mutableCopy],
                              [@[] mutableCopy],
                              [@[] mutableCopy]];
    
    [array enumerateObjectsUsingBlock:^(id object, NSUInteger idx, BOOL *stop) {
            [resultArrays[idx % resultArrays.count] addObject:object];
    }];
    

    您应该想到在 Objective-C 类别中创建可重用的代码:

    @interface NSArray (SplittingInto)
    -(NSArray *)arraysBySplittingInto:(NSUInteger)N;
    @end
    
    @implementation NSArray (SplittingInto)
    -(NSArray *)arraysBySplittingInto:(NSUInteger)N
    {
        NSAssert(N > 0, @"N cant be less than 1");
        NSMutableArray *resultArrays = [@[] mutableCopy];
        for (NSUInteger i =0 ; i<N; ++i) {
            [resultArrays addObject:[@[] mutableCopy]];
        }
    
        [self enumerateObjectsUsingBlock:^(id object, NSUInteger idx, BOOL *stop) {
                                    [resultArrays[idx% resultArrays.count] addObject:object];
                                }];
        return resultArrays;
    }
    @end
    

    现在你可以做

    NSArray *array = [@[@1,@2,@3,@4,@5,@6,@7,@8,@9,@10,@11,@12] arraysBySplittingInto:2];
    

    array 包含

    (
            (
            1,
            3,
            5,
            7,
            9,
            11
        ),
            (
            2,
            4,
            6,
            8,
            10,
            12
        )
    )
    

    【讨论】:

    • 并发解决方案需要锁定可变数组。
    • 要使用并发,您可以调度两个操作,一个用于even,一个用于odd 数组,并枚举原始数组两次。对于非常大的数组,这可能会加快速度。
    • 好了,这就是我的答案。 写了一个并发的解决方案被破坏了。现在我编写了工作并发解决方案并对其进行了基准测试。 PS:我没有投票给你。
    • NSMutableArray 不是线程安全的,因此同时对其进行变异会导致某些元素丢失。 en.wikipedia.org/wiki/Synchronization_(computer_science)
    • 我删除了并发选项,因为它实际上是这个问题的范围。
    【解决方案2】:

    创建两个NSIndexSets,一个用于偶数索引,一个用于奇数索引,然后使用objectsAtIndexes: 提取数组的相应切片。

    【讨论】:

      【解决方案3】:

      您可以通过以下方式实现:-

      上面两个已经提到了第一个和第二个解决方案。以下是相同的实现:-

      //First Solution
      NSArray *ar=@[@"1",@"2",@"3",@"4",@"5"];
      NSMutableArray *mut1=[NSMutableArray array];
      NSMutableArray *mut2=[NSMutableArray array];
      [ar enumerateObjectsUsingBlock:^(id object, NSUInteger idx, BOOL *stop) {
          if (idx%2==0)
          {
              [mut1 addObject:object];
          }
          else
          {
              [mut2 addObject:object];
          }
      }];
      
      //Second Solution
      NSMutableIndexSet *idx1 = [NSMutableIndexSet indexSet];
      NSMutableIndexSet *idx2 = [NSMutableIndexSet indexSet];
      for (NSUInteger index=0; index <ar.count(); index++)
      {
         if(index%2==0)
          {
              [idx1 addIndex:index];
          }
          else{
              [idx2 addIndex:index];
          }
      }
      NSArray *evenArr=[ar objectsAtIndexes:idx1];
      NSArray *oddArr=[ar objectsAtIndexes:idx2];
      NSLog(@"%@",evenArr);
      NSLog(@"%@",oddArr);
      

      【讨论】:

      • 使用“for in”循环和indexOfObject 效率极低。
      • 为什么不像第一个解决方案一样在第二个和第三个解决方案中使用enumerateObjects...
      • 这就是解决方案,您还提供了代码示例,非常感谢!
      • 解决方案 3 是解决方案 1 的一个有问题的版本。c 样式的 for 循环不提供突变保护并且速度很慢。
      【解决方案4】:

      有时间进行基准测试,结果发现当输入数组超过1000万时,使用并行执行会更快。

      这里是并发解决方案,它枚举输入数组两次以防止输出数组出现竞争条件。

      static NSArray * concurrent(NSArray *input) {
          NSUInteger capacity = input.count / 2;
          NSArray *split = @[
                             [NSMutableArray arrayWithCapacity:capacity],
                             [NSMutableArray arrayWithCapacity:capacity],
                             ];
          [split enumerateObjectsWithOptions:NSEnumerationConcurrent
                                  usingBlock:^(NSMutableArray *output, NSUInteger evenOdd, BOOL *stop) {
                                      [input enumerateObjectsUsingBlock:^(id object, NSUInteger index, BOOL *stop) {
                                          if (index % 2 == evenOdd) {
                                              [output addObject:object];
                                          }
                                      }];
                                  }];
          return split;
      }
      

      我认为这是最佳串行解决方案,因此我将其用于基准测试:

      static NSArray * serial(NSArray *input) {
          NSUInteger capacity = input.count / 2;
          NSMutableArray *even = [NSMutableArray arrayWithCapacity:capacity];
          NSMutableArray *odd = [NSMutableArray arrayWithCapacity:capacity];
      
          [input enumerateObjectsUsingBlock:^(id object, NSUInteger index, BOOL *stop) {
              NSMutableArray *output = (index % 2) ? odd : even;
              [output addObject:object];
          }];
          return @[ even, odd ];
      }
      

      结果

      • 100 万个元素
        • 序列号:54.081 毫秒
        • 并发:65.958 毫秒(差 18%)
      • 1000 万个元素
        • 序列号:525.851 毫秒
        • 并发:412.691 毫秒提高 27%
      • 一亿个元素
        • 序列号:5244.798 毫秒
        • 并发:4137.939 毫秒提高 27%

      平均运行 5 次。
      输入填充为NSNumbers
      最快最小优化-Os.

      【讨论】:

      • 您的并发实现是半并发的,因为它最多使用 2 个线程。
      • @vikingosegundo 并发=不止一个。在构建两个数组时,最多可以使用两个线程。
      • 那不是真的。您可以使用几个临时数组并在以后加入它们。或者可以使用 c 数组。或者……我只想指出,使用更复杂的算法可以实现更高程度的并发。但这超出了问题的范围,正如bbum said:通过从串行执行转移到并发执行来解决性能问题通常会导致两个问题:性能和并发性。
      猜你喜欢
      • 2012-09-06
      • 2011-12-28
      • 1970-01-01
      • 2021-05-25
      • 1970-01-01
      • 2011-10-15
      • 1970-01-01
      • 2022-10-01
      • 1970-01-01
      相关资源
      最近更新 更多