私はそのNSMutableArray
中にいくつかを持っていますNSDecimalNumber
、のように(500,50.80,70,8000)
decimal numbers
今、私はそれらすべてを一緒に追加したいと思います。
使ってみました
for (NSDecimalNumber *number in self.numbersArray)
{
NSDecimal *sum += [number decimalValue]
}
しかし失敗しました。
私はそのNSMutableArray
中にいくつかを持っていますNSDecimalNumber
、のように(500,50.80,70,8000)
decimal numbers
今、私はそれらすべてを一緒に追加したいと思います。
使ってみました
for (NSDecimalNumber *number in self.numbersArray)
{
NSDecimal *sum += [number decimalValue]
}
しかし失敗しました。
配列にすべてのsを追加する簡単な方法NSNumber
は、次のとおりです(@Mahonorがコメントで言ったことと同様)。
NSArray *myArray = ... // array of NSNumber (or NSDecimalNumber) objects
NSNumber *sum = [myArray valueForKeyPath:@"@sum.self"];
コレクション演算子:sumの状態とは異なり、配列内の数値はに変換されませんdouble
が、に変換されNSDecimal
ます。したがって、10進数を加算するときに精度が失われることはありません。NSNumber
10進数ではないオブジェクトでもNSDecimal
、加算のために変換されます。合計の結果はのインスタンスですNSDecimalValue
。
私は2つの異なる方法でそれを検証しました(または試みました)。まず、このコードを実行しました
NSNumber *a = [NSNumber numberWithDouble:1.2];
NSNumber *b = [NSDecimalNumber decimalNumberWithString:@"-5.7"];
NSArray *myArray = @[a, b];
id sum = [myArray valueForKeyPath:@"@sum.self"];
環境変数「NSObjCMessageLoggingEnabled=YES」を設定して、Objective-Cメッセージロギングをアクティブにしました。作成された「/tmp/ msgSends-NNNN」ファイルに見られるように、decimalNumber
(ではなくdoubleValue
)両方の番号オブジェクトに送信されます。
次に、との両方decimalValue
を実装するカスタムクラスを作成し、カスタムクラスのオブジェクトの配列にdoubleValue
適用しました。@sum.self
@interface MyClass : NSObject
@property (nonatomic, assign) double value;
@end
@implementation MyClass
- (NSDecimal)decimalValue
{
return [[NSNumber numberWithDouble:self.value] decimalValue];
}
- (double)doubleValue
{
return self.value;
}
@end
MyClass *a = [MyClass new]; a.value = 1.2;
MyClass *b = [MyClass new]; b.value = -5.7;
NSArray *myArray = @[a, b];
id sum = [myArray valueForKeyPath:@"@sum.self"];
両方のメソッドにブレークポイントを設定することによりdecimalValue
、合計にのみ使用されることがわかります(valueForKeyPath:@"@sum.self"
クラスが実装されていない場合は例外をスローしますdecimalValue
)。
decimalValue
それがから呼び出されていることもわかります
-[NSArray(NSKeyValueCoding) _sumForKeyPath:]
このメソッドのアセンブラコードはNSDecimalAdd
、が数値の加算に使用されることを示しています。
使用する- (NSDecimalNumber *)decimalNumberByAdding:(NSDecimalNumber *)decimalNumber
NSDecimalNumberクラスリファレンスをご覧ください
NSDecimalNumber *lNumber = [NSDecimalNumber zero];
for (NSDecimalNumber *number in self.numbersArray)
{
lNumber = [lNumber decimalNumberByAdding:number];
}
コメントでのマノハールの提案は悪くない。実際、KVCコレクション演算子を使用してこれからワンライナーを作成することはでき[myArray valueForKeyPath:@"@sum.doubleValue"];
ますが、精度が低下する可能性があります(保存した数値によって異なります)。
基本的に「削減」機能を探しています。decimalNumberByAdding:
各呼び出しが引数として配列の後続要素を持つように、呼び出しをチェーンする必要があります。でこれを行うのNSArray
は簡単です。performSelector:withObject:
@implementation NSArray (Reduce)
- (id)reduceUsingSelector: (SEL)sel
{
id res = [self objectAtIndex:0];
for( id obj in [self subarrayWithRange:(NSRange){1, [self count]-1}] ){
res = [res performSelector:sel withObject:obj];
}
return res;
}
@end
次のように使用します。NSDecimalNumber * sum = [myArray reduceUsingSelector:@selector(decimalNumberByAdding:)];
NSDecimal
構造体であり、オブジェクトではないため、使用しているコードは成功しません。ポインタとして宣言するべきではありません。宣言しないと、追加できません。それは解決策への正しい道ではありません。