Связанные выражения для выполнения вычислений в Core Data
Прежде всего: с новым годом:-)
Что я пытаюсь сделать
Я пытаюсь разделить два атрибута в Базовых данных и затем вычислить среднее из этих делений. Атрибуты указываются путем ключа (например, eur
, usd
, aud
).
Пример: у меня есть следующий набор данных:
date eur usd aud
------------------------------
2010-01-01 0.5 1.0 1.5
2010-01-02 0.6 1.1 1.6
2010-01-03 0.4 1.0 1.3
Разделите два атрибута, например, eur / usd на следующие результаты...
divide eur / usd:
------------------
2010-01-01 0.5
2010-01-02 0.54
2010-01-03 0.4
... затем вычислите среднее значение этих чисел (0.5 + 0.54 + 0.4)/3 = 0.48
Мой код
Поскольку я хотел бы, чтобы эти вычисления выполнялись непосредственно с помощью Core Data, я создал следующие выражения и запрос на выборку:
NSExpression *fromCurrencyPathExpression = [NSExpression
expressionForKeyPath:fromCurrency.lowercaseString];
NSExpression *toCurrencyPathExpression = [NSExpression
expressionForKeyPath:toCurrency.lowercaseString];
NSExpression *divisionExpression = [NSExpression
expressionForFunction:@"divide:by:"
arguments:@[fromCurrencyPathExpression,
toCurrencyPathExpression]];
NSExpression *averageExpression = [NSExpression expressionForFunction:@"average:"
arguments:@[divisionExpression]];
NSString *expressionName = @"averageRate";
NSExpressionDescription *expressionDescription =
[[NSExpressionDescription alloc] init];
expressionDescription.name = expressionName;
expressionDescription.expression = averageExpression;
expressionDescription.expressionResultType= NSDoubleAttributeType;
NSFetchRequest *request = [NSFetchRequest
fetchRequestWithEntityName:NSStringFromClass([self class])];
NSPredicate *predicate =
[NSPredicate predicateWithFormat:@"date >= %@ AND date <= %@",startDate,fiscalPeriod.endDate];
request.predicate = predicate;
request.propertiesToFetch = @[expressionDescription];
request.resultType = NSDictionaryResultType;
NSError *error;
NSArray *results = [context
executeFetchRequest:request error:&error];
Эта проблема
Однако при запуске приложения оно вылетает с сообщением об ошибке:
Unsupported argument to sum : (
"eur / usd"
Что не так с моим кодом? Как связать два вычисления и выполнить их непосредственно в Базовых данных?
Спасибо!
1 ответ
Кажется, что "коллекция" функции выражения, такие как @average
может использоваться только с ключевыми путями, но не в сочетании с другими общими выражениями, если используется как propertiesToFetch
, У меня нет ссылки на это, но это проблема, которую заметили и другие:
- Получить совокупные данные из NSManagedObject, используя другое выражение в качестве аргумента для суммирования: выражения
- Выполнение умножения (агрегации) с CoreData: как?
Таким образом, вы могли бы выполнить два шага: сначала выполнить запрос выборки, который возвращает массив с результатами всех делений:
NSExpression *fromCurrencyPathExpression = [NSExpression
expressionForKeyPath:@"eur"];
NSExpression *toCurrencyPathExpression = [NSExpression
expressionForKeyPath:@"usd"];
NSExpression *divisionExpression = [NSExpression
expressionForFunction:@"divide:by:"
arguments:@[fromCurrencyPathExpression,
toCurrencyPathExpression]];
NSString *expressionName = @"ratio";
NSExpressionDescription *expressionDescription =
[[NSExpressionDescription alloc] init];
expressionDescription.name = expressionName;
expressionDescription.expression = divisionExpression;
expressionDescription.expressionResultType= NSDoubleAttributeType;
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Entity"];
request.propertiesToFetch = @[expressionDescription];
request.resultType = NSDictionaryResultType;
NSError *error;
NSArray *ratios = [context executeFetchRequest:request error:&error];
В результате получается массив словарей:
(lldb) po ratios
(NSArray *) $0 = 0x00000001001170f0 <_PFArray 0x1001170f0>(
{
ratio = "0.5454545454545454";
},
{
ratio = "0.4";
},
{
ratio = "0.5";
}
)
Также, с опцией "-com.apple.CoreData.SQLDebug 1" можно увидеть, что деления уже выполнены на уровне SQLite:
sql: SELECT t0.ZEUR / t0.ZUSD FROM ZENTITY t0
Затем вы можете вычислить среднее значение всех соотношений в памяти, используя кодирование значения ключа:
NSNumber *average = [ratios valueForKeyPath:@"@avg.ratio"];
и результат
(lldb) po average
(NSNumber *) $0 = 0x000000010012fd60 0.4818181818181818