【问题标题】:NSArray Loop to grab ObjectsNSArray 循环抓取对象
【发布时间】:2011-09-22 20:23:46
【问题描述】:

我目前正在开发一个应用程序,该应用程序需要能够从 NSArray 中获取两个对象,然后将其存储在另一个对象中。

我目前正在进行这个快速枚举循环,

NSUInteger count = 0;
NSUInteger i = count + 1;
for (id item in [section items]) {


    item1 = [section.items objectAtIndex:count];
    item2 = [section.items objectAtIndex:i];

    count++;

}

现在,我要做的是抓取第一个位置的对象并存储在 item1 中,然后将第二个位置存储在 item2 中。下次它通过循环时,我希望它将对象存储在 item1 的第三个位置,然后是 item2 的第四个位置,依此类推。

有没有人尝试过并实现了这一点?

编辑

这就是我目前所拥有的,我认为最好我更深入地解释我正在做的事情,所以就到这里吧。这是我首先拥有的代码,稍后我会解释。

MPSection *section = [self.sections objectAtIndex:indexPath.section];

NSArray *itemArray = [section items];
for (NSUInteger i = 0; (i + 1) < [section.items count]; i += 2) {
    item1 = [itemArray objectAtIndex:i];
    item2 = [itemArray objectAtIndex:i+1];
}

如您所见,这是在(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 中运行的,因为我想获取通常会在 UITableView 的第一行和第二行中显示的内容,并将其放入一个单元格中,该单元格分为两个子视图。

我发现,通过使用上面的代码,它肯定没有这样做。有没有更简单的方法可以做到这一点,如果是这样,有人可以告诉我这一点。我真的需要通过将内存保留和时间消耗保持在最低限度来解决这个问题。

【问题讨论】:

  • MPSection *section = [self.sections objectAtIndex:indexPath.row]; 正确吗?还是你的意思是MPSection *section = [self.sections objectAtIndex:indexPath.section];?

标签: objective-c ipad object for-loop nsarray


【解决方案1】:

如果您可以对此进行预处理,那就太好了,但如果由于某种原因您不能这样做,那么这就是您应该做的,

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    MPSection * section = [self.sections objectAtIndex:section];
    NSInteger   count   = [section.items count];

    return ((count % 2 == 0)? count / 2 : (count / 2 + 1) );
}

tableView:cellForRowAtIndexPath:方法中,

/* */

MPSection *section = [self.sections objectAtIndex:indexPath.section];

id item1 = [section.items objectAtIndex:(indexPath.row * 2)];
id item2 = ((indexPath.row * 2 + 1) < [section.items count])? [section.items objectAtIndex:(indexPath.row * 2 + 1)] : nil;

/* Use item1 & item2 to fill both the subviews */

原答案

为此目的使用NSEnumerator 实例

NSEnumerator *enumerator = [section.items objectEnumerator];
id item1, item2;
while ( (item1 = [enumerator nextObject]) && (item2 = [enumerator nextObject]) ) {
    // Use item1 & item2
}

因此,我认为您提到的 sn-p 的 index out of bounds 错误。

矫枉过正

似乎有一些关于性能的问题,所以我测试了三个建议的方法,并在我记录它们的循环中对它们进行计时。

Enumerator, Fast Enumeration with Object Search, For Loop (50000 elements): 19.253626, 88.269961, 18.767572
Enumerator, Fast Enumeration with Object Search, For Loop (25000 elements): 9.164311, 25.105664, 8.777443
Enumerator, Fast Enumeration with Object Search, For Loop (10000 elements): 3.428265, 6.035876, 3.144609
Enumerator, Fast Enumeration with Object Search, For Loop (5000 elements): 2.010748, 2.548562, 1.980477
Enumerator, Fast Enumeration with Object Search, For Loop (1000 elements): 0.508310, 0.389402, 0.338096
Enumerator, Fast Enumeration with Object Search, For Loop (500 elements): 0.156880, 0.163541, 0.150585
Enumerator, Fast Enumeration with Object Search, For Loop (100 elements): 0.076625, 0.034531, 0.036576
Enumerator, Fast Enumeration with Object Search, For Loop (50 elements): 0.026115, 0.022686, 0.041745

从外观上看,@Caleb 的 for 循环方法可能是最好的方法。

【讨论】:

  • 他显然在使用 NSFastEnumeration,它会自动处理枚举。我觉得这有点矫枉过正。
  • 为什么要矫枉过正?这是一个比快速枚举更好的解决方案,它会强制您一次获取一个对象。此解决方案采用成对的对象,这正是 OP 正在寻找的。​​span>
  • 太好了——感谢您抽出宝贵时间进行测试!用 200,000、300,000 和 400,000 个对象测试用例可能会很有趣——显然是300,000 is where NSArray will surprise you
  • 顺便说一句,我最喜欢你的解决方案。它可能比我的传统 for 循环稍慢,并且在功能上等同于我的枚举器解决方案,但是将两个赋值都放在条件中是干净的,并且直接表达了 OP 表达的意图。
  • 与其他两种方法相比,NSEnumerator 方法对 200,000 个项目更有效,但我怀疑 OP 是否处理了这么多项目。那个链接很好读。 +1
【解决方案2】:

如果您不喜欢在这里使用快速枚举,您可以设置一个标志,让您跳过循环的每个偶数迭代:

BOOL doThisOne = YES;
NSArray itemArray = [section itemArray];
for (id item in items) {
    if (doThisOne) {
        item1 = item;
        item2 = [itemArray objectAtIndex:1+[itemArray indexOfObject:item]];
    }
    doThisOne = !doThisOne;
}

注意: 如果数组中的项目数为奇数,上面的代码将引发范围异常。其他一些答案避免了这种情况,但我认为最好的答案就是不要在这里使用快速枚举。

使用枚举器会简单得多,或者只使用常规的旧 for 循环:

NSEnumerator *e = [[section items] objectEnumerator];
while (item = [e nextObject]) {
    item1 = item;
    item2 = [e nextObject];
}

或:

NSArray *itemArray = [section items];
for (int i = 0; (i + 1) < [items count]; i += 2) {
    item1 = [items objectAtIndex:i];
    item2 = [items objectAtIndex:i+1];
}

【讨论】:

    【解决方案3】:
    for(id item in array){
        if([array indexOfObject:item] % 2 != 0){
         item1 = item;
        }else{
         item2 = item;
        }
    }
    

    【讨论】:

    • 有趣的方法 Chris...但我不确定 -[indexOfObject:] 在 O(1) 中运行。即使是这样,它是否比涉及 for 循环和局部索引变量的“明显”答案更昂贵? - “匿名”评论家
    • 我不会说一个比另一个更“明显”,这就是我首先解决问题的方法。这是一个偶数/奇数问题,所以我认为这是解决它的最简单方法。就性能而言,局部索引变量可能(可能)成本更低,但我坚持我的模数方法。
    • 我认为问题不在于模数,而在于 -indexOfObject: 方法是否需要搜索数组以查找给定对象的索引。这可能是 O(1) 操作,也可能是 O(n)。如果是后者,整个循环可能变成 O(n^2) 而不是 O(n),显然是不可取的。
    • 哦,我知道你在说什么。显然,数组越往下比较对象以获得索引,运行循环所需的时间就越长。这就是为什么我说它可能会更快。如果它是一个约 50 个对象的数组,我认为差异应该可以忽略不计。如果您希望代码可扩展到大型数组,那您当然是正确的。
    • 假设,如果每个循环的每次迭代需要 1 ms 来执行,并且如果 n == 50,那么 O(n^2) 解决方案将需要 2.5 s 来运行,而不是 50 ms O(n) 解决方案需要运行。
    【解决方案4】:
    int numItems = [section.items count];
    
    for(int i = 0; i < count; i++) {
        item1 = [section.items objectAtIndex: i];
        item2 = ((i + 1) < count)) ? [section.items objectAtIndex: (i + 1)] : nil;
    } 
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多