【问题标题】:Unexpected behaviour when inserting object into NSMutableArray将对象插入 NSMutableArray 时出现意外行为
【发布时间】:2013-02-02 17:13:36
【问题描述】:

所以我一直在研究 Objective-C 中的 Project Euler 问题 25,但遇到了 NSDecimalNumber 的大小限制。因此,在尝试使用其他代码库之后,我决定重新表示我的斐波那契数,首先是 ints 的数组,然后是 NSArrays 的 NSNumbers 的数组。数组中的每个单元格都是一个数字。然后我可以将大数逐位加到第 1000 位。不幸的是,出了点问题,我的进位是正确的,但最后一个进位之前的数字似乎总是为零。

我尝试计算第 8 个斐波那契数和第 12 个斐波那契数并得到相同的行为。我没有得到 13 和 144,而是得到 10 和 104。我正确地对数字求和,但是

[nextFib insertObject: [NSNumber numberWithInt:digitSum] atIndex: arrayIndex]; 

似乎没有达到我的预期。在这两种情况下,digitSum 都是 3 和 4,但是一旦我的方法将下一个斐波那契数作为 NSArray 返回,我就会得到一个 0,而我期望它是 3 或 4。我尝试过它,但我很困惑。它似乎在某些时候有效,但其他时候我动态创建的 NSNumber 没有我期望的值。这是我的整个方法:

+ (NSArray*) nextBigFibonancci: (NSArray*) fibZero After: (NSArray*) fibOne
{
  // It's come to manually adding digits in one thousand count arrays.
  // I can't return or pass arrays... will have to use NSArrays for everything, version at least 4.0
  // Since XCode 4.5 I can use array[i] and other array literals... Lets just get it working...

  // Works for Fib 1 and Fib 2 and Fib 3, but not Fib 12...

  int fibZeroDigits = [fibZero count];
  int fibOneDigits = [fibOne count];
  NSMutableArray*  nextFib = [NSMutableArray arrayWithCapacity:1000];
  NSArray* number;
  int arrayIndex = 999;
  int cellCount = fibZeroDigits - 1;
  int digitZero, digitOne, digitSum;

  // There is an Objective-c loop structure for looping through all objects in array, but stick to this...
  for (int j = 0; j < 1000; j++)
  {
    // All the integers must be zero.
    [nextFib insertObject: [NSNumber numberWithInt:0] atIndex: j];
  }

  for (int i = fibOneDigits; i > 0; i--)
  {
    digitZero = [[fibZero objectAtIndex: cellCount] intValue];
    digitOne = [[fibOne objectAtIndex: i - 1] intValue];
    NSLog(@"arrayIndex is: %i", arrayIndex); // arrayIndex seems correct why am I getting 104?
    if (digitZero + digitOne < 10)
    {
        digitSum = digitZero + digitOne + [[nextFib objectAtIndex: arrayIndex] intValue];
        [nextFib insertObject: [NSNumber numberWithInt:digitSum] atIndex: arrayIndex];
    }
    else
    {
        digitSum = digitZero + digitOne - 10 + [[nextFib objectAtIndex:arrayIndex] intValue];
        // This isn't working the second time, though digitSum is added correctly...
        // Getting 1,0,4 for fibTwelve instead of 144
        // Doesn't work for fibEight get 1,0 instead of 13...
        [nextFib insertObject: [NSNumber numberWithInt:digitSum] atIndex: arrayIndex]; 
        [nextFib insertObject: [NSNumber numberWithInt: 1] atIndex: arrayIndex -1];
    }
    arrayIndex = arrayIndex - 1;
    cellCount = cellCount - 1;
  }
  // Must carry the last digit in fibOne if arrays are of different sizes...

  if (fibZeroDigits < fibOneDigits)
  {
    // fibOne has one extra digit
    digitSum = [[fibOne objectAtIndex:0] intValue] + [[nextFib objectAtIndex:arrayIndex - 1] intValue];
    [nextFib insertObject:[NSNumber numberWithInt:digitSum] atIndex:arrayIndex -1];
  }

  // Shouldn't return nextFib, but only the signifigant, ie non zero integers

  // Find first non zero digit and then the range from there until the end of the array nextFib
  for(int n = 0; n < 1000; n++)
  {
    if ([[nextFib objectAtIndex: n] intValue] > 0)
    {
        // First non zero digit.
        NSRange theRange;

        theRange.location = n;
        theRange.length = 1000 - n;

        number = [nextFib subarrayWithRange:theRange];
        break; // Could set n = 1000 which would also break...
     }
   }


  return number;
}

任何想法为什么我用它创建的digitSumNSNumber 在需要携带时没有按预期存储?

【问题讨论】:

  • 我最大的 bug 是使用 insertObjectAtIndex: 而不是 replaceObjectAtIndex: withObject: 造成的,但上面的代码中也有其他 bug。
  • 恭喜,您对第 25 题的回答是正确的。您是第 60154 位解决此问题的人。
  • 我修复了我的代码,然后从我的 main.m 运行它,直到我得到一个 1000 位长的术语。

标签: objective-c cocoa nsmutablearray


【解决方案1】:

如上所述,我发现了自己的错误以及更多错误。 insertObjectAtIndex 向 NSMutableArray 添加了一个全新的对象,我想用新计算的数字替换之前的数字。

XCode 刚刚更新添加了从调试器查看 NSArrays 内部的功能,正如我在上面提到的那样,这本来很好。这是添加两个 1000 位数字的方法,可以修改它以添加更大的数字,它们甚至不必是斐波那契数。

+ (NSArray*) nextBigFibonancci: (NSArray*) fibZero After: (NSArray*) fibOne
{    
    int fibZeroDigits = [fibZero count];
    int fibOneDigits = [fibOne count];
    int loops = fibZeroDigits - 1;
    int fibOneIndex = loops;
    NSMutableArray*  nextFib = [NSMutableArray arrayWithCapacity:1000];
    NSArray* number;
    int arrayIndex = 999;
    int digitZero, digitOne, digitSum;

    // There is an Objective-c loop structure for looping through all objects in array, but I'll just stick to this...
    for (int j = 0; j <= arrayIndex; j++) 
    {
        // All the integers start at zero.
        [nextFib insertObject: [NSNumber numberWithInt:0] atIndex: j];
    }

    if (fibOneDigits > fibZeroDigits)
    {
        fibOneIndex++;
    }

    for (int i = loops; i >= 0; i--)
    {
        digitZero = [[fibZero objectAtIndex: i ] intValue];
        digitOne = [[fibOne objectAtIndex: fibOneIndex ] intValue];
        // Have to use replaceObjectAtIndex not insertObjectAtIndex!
        digitSum = digitZero + digitOne + [[nextFib objectAtIndex: arrayIndex] intValue];
        if (digitSum < 10)
        {
            [nextFib replaceObjectAtIndex: arrayIndex withObject: [NSNumber numberWithInt:digitSum]];
        }
        else
        {
            digitSum = digitSum - 10;
            [nextFib replaceObjectAtIndex: arrayIndex withObject: [NSNumber numberWithInt:digitSum]];
            [nextFib replaceObjectAtIndex: arrayIndex -1 withObject: [NSNumber numberWithInt:1]];
        }
        arrayIndex = arrayIndex - 1;
        fibOneIndex = fibOneIndex -1;
    }
    // Must carry the last digit in fibOne if arrays are of different sizes...

    if (fibZeroDigits < fibOneDigits)
    {
        // fibOne has one extra digit
        digitSum = [[fibOne objectAtIndex:0] intValue] + [[nextFib objectAtIndex:arrayIndex] intValue];
        [nextFib replaceObjectAtIndex: arrayIndex withObject: [NSNumber numberWithInt:digitSum]];
    }

    // Shouldn't return nextFib, but only the signifigant, ie non zero integers
    // Find first non zero digit and then the range from there until the end of the array nextFib
    for(int n = 0; n < 1000; n++)
    {
        if ([[nextFib objectAtIndex: n] intValue] > 0)
        {
            // First non zero digit.
            NSRange theRange;

            theRange.location = n;
            theRange.length = 1000 - n;  

            number = [nextFib subarrayWithRange:theRange];
            break; // Could set n = 1000 which would also break...
        }
    }


    return number;
}

【讨论】:

    【解决方案2】:

    我还使用了 NSNumbers 的 NSArray 来解决这个问题。如果您以相反的顺序存储斐波那契数字的数字,则可以使用更少的代码。

    我创建了一个有 2 个参数的方法,两个 NSArrays 都代表斐波那契数,它返回一个代表下一个数字的 NSArray。因此,要通过将 89 和 144 相加来计算第 13 个斐波那契数,方法两个参数的值是 [9, 8] & [4, 4, 1],它返回 [3, 3, 2]。

    我认为您会发现以这种方式“携带”更简单。如果你是天才数学家,显然there's also a way to solve this on paper

    【讨论】:

    • 我知道我的答案不是最优的,它甚至不起作用,但我仍然想知道为什么当调试器中的 digiSum = 3 并且我使用 digiSum 创建一个 NSNumber 并将其存储在 NSMutableArray 中然后取一个子数组并从此方法返回它,当我读取 NSNumber intValues 时,我的 3 变为 0?
    • 您最近对这个问题的 cmet 说您解决了这个问题。这是否意味着您已经回答了自己的问题并且您的代码正在运行?
    • 我的代码正在运行,我应该做更多的事情来关闭线程吗?我不认为我有这个权力。问题是 insertObjectAtIndex 添加了一个新对象并将所有内容向左或向右移动,其中 replaceObjectAtIndexWith 用我计算的一个替换了当前的零位,但还有其他错误。 Xcode 更新具有检查 NSArrays 和 NSMutableArrays 的能力,这将有助于调试,但我只是使用 NSLog...
    • 是的,您可以通过接受答案(甚至是您自己提供的答案)或删除问题来关闭它。接受答案会告诉其他人他们不再需要尝试解决这个问题。我很高兴你能成功。
    • 我不得不谷歌如何回答一个问题,幸运的是有一个讨论线程。 ;-)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-04
    • 1970-01-01
    • 2023-03-17
    • 1970-01-01
    相关资源
    最近更新 更多