Какой эффективный и отличный способ сравнить все значения NSArray
, содержащие NSNumbers
от floats
, чтобы найти самый большой и самый маленький?
Любые идеи, как сделать это красиво и быстро в objective-c
?
Какой эффективный и отличный способ сравнить все значения NSArray
, содержащие NSNumbers
от floats
, чтобы найти самый большой и самый маленький?
Любые идеи, как сделать это красиво и быстро в objective-c
?
Если скорость выполнения (не скорость программирования) важна, то явный цикл является самым быстрым. Я провел следующие тесты с массивом из 1000000 случайных чисел:
Версия 1: сортировка массива:
NSArray *sorted1 = [numbers sortedArrayUsingSelector:@selector(compare:)];
// 1.585 seconds
Версия 2: кодирование с ключом, используя "doubleValue":
NSNumber *max=[numbers valueForKeyPath:@"@max.doubleValue"];
NSNumber *min=[numbers valueForKeyPath:@"@min.doubleValue"];
// 0.778 seconds
Версия 3: кодирование с ключом, используя "self":
NSNumber *max=[numbers valueForKeyPath:@"@max.self"];
NSNumber *min=[numbers valueForKeyPath:@"@min.self"];
// 0.390 seconds
Версия 4: Явный цикл:
float xmax = -MAXFLOAT;
float xmin = MAXFLOAT;
for (NSNumber *num in numbers) {
float x = num.floatValue;
if (x < xmin) xmin = x;
if (x > xmax) xmax = x;
}
// 0.019 seconds
Версия 5: Перечисление блоков:
__block float xmax = -MAXFLOAT;
__block float xmin = MAXFLOAT;
[numbers enumerateObjectsUsingBlock:^(NSNumber *num, NSUInteger idx, BOOL *stop) {
float x = num.floatValue;
if (x < xmin) xmin = x;
if (x > xmax) xmax = x;
}];
// 0.024 seconds
Программа тестирования создает массив из 1000000 случайных чисел, а затем применяет все сортировки методы для одного и того же массива. Вышеуказанные тайминги являются результатом одного запуска, но я делаю около 20 прогонов с очень похожими результатами в каждом прогоне. Я также изменил порядок, в котором применяются 5 методов сортировки для исключения эффектов кеширования.
Обновление: Я создал (надеюсь) лучшую тестовую программу. Полный исходный код находится здесь: https://gist.github.com/anonymous/5356982. Среднее время для сортировки массив из 1000000 случайных чисел (в секундах, на 3,1 ГГц Core i5 iMac, выпуск компиляции):
Sorting 1.404 KVO1 1.087 KVO2 0.367 Fast enum 0.017 Block enum 0.021
Обновление 2: Как видно, быстрое перечисление выполняется быстрее, чем перечисление блоков (что также указано здесь: http://blog.bignerdranch.com/2337-incremental-arrayification/).
РЕДАКТИРОВАТЬ: Неправильно следующее: я забыл инициализировать объект, используемый как блокировка, как правильно заметил Hot Licks, так что синхронизация вообще не выполняется.
И с lock = [[NSObject alloc] init];
параллельное перечисление настолько медленное
что я не осмеливаюсь показать результат. Возможно, более быстрый механизм синхронизации может
помощь...)
Это резко меняется, если вы добавите параметр NSEnumerationConcurrent
к
перечисление блока:
__block float xmax = -MAXFLOAT;
__block float xmin = MAXFLOAT;
id lock;
[numbers enumerateObjectsWithOptions:NSEnumerationConcurrent usingBlock:^(NSNumber *num, NSUInteger idx, BOOL *stop) {
float x = num.floatValue;
@synchronized(lock) {
if (x < xmin) xmin = x;
if (x > xmax) xmax = x;
}
}];
Сроки здесь
Concurrent enum 0.009
так что это примерно в два раза быстрее, чем быстрое перечисление. Результат, вероятно, не является репрезентативным потому что это зависит от количества доступных потоков. Но интересно все равно! Обратите внимание, что я использовали "самый простой в использовании" метод синхронизации, который может быть не самым быстрым. Забастовкa >
Сохранить float путем упаковки под NSNumber, затем
NSNumber *max=[numberArray valueForKeyPath:@"@max.doubleValue"];
NSNumber *min=[numberArray valueForKeyPath:@"@min.doubleValue"];
* Не скомпилирован и не проверен, уже проверен с помощью intValue, не уверен в двойном или float
сортировать. возьмите первый и последний элементы.
btw: вы не можете хранить float в NSArray, вам нужно будет обернуть их в объекты NSNumber.
NSArray *numbers = @[@2.1, @8.1, @5.0, @.3];
numbers = [numbers sortedArrayUsingSelector:@selector(compare:)];
float min = [numbers[0] floatValue];
float max = [[numbers lastObject] floatValue];
Я соглашаюсь на сортировку массива, затем выбор первого и последнего элементов, но я считаю это решение более элегантным (это также будет работать для не числовых объектов, изменив сравнение внутри блока):
NSArray *unsortedArray = @[@(3), @(5), @(1)];
NSArray *sortedArray = [unsortedArray sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
NSNumber *item1 = (NSNumber *)obj1;
NSNumber *item2 = (NSNumber *)obj2;
return [item1 compare:item2];
}];
Если вы действительно хотите получить фантазию и иметь действительно длинный список, и вы не хотите блокировать свой основной поток, это должно работать:
NSComparator comparison = ^NSComparisonResult(id obj1, id obj2) {
NSNumber *item1 = (NSNumber *)obj1;
NSNumber *item2 = (NSNumber *)obj2;
return [item1 compare:item2];
};
void(^asychSort)(void) = ^
{
NSArray *sortedArray = [unsortedArray sortedArrayUsingComparator:comparison];
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"Finished Sorting");
//do your callback here
});
};
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), asychSort);
Сделано просто
NSArray *numbers = @[@2.1, @8.1, @5.0, @.3];
numbers = [numbers sortedArrayUsingSelector:@selector(compare:)];
float min = [numbers[0] floatValue];
float max = [[numbers lastObject] floatValue];
NSLog(@"MIN%f",min);
NSLog(@"MAX%f",max);
Любой, кто ищет Swift 3.x -
let arrayOfNumbers = [1.0,4.2,10.3,15.2]
print(arrayOfNumbers.max() ?? 0.0)//Max number
print(arrayOfNumbers.min() ?? 0.0)//Min number