Коли краще використовувати NSSet над NSArray?


112

Я багато разів використовував NSSets у своїх додатках, але сам ніколи не створював.

Коли краще використовувати на NSSetвідміну від NSArrayі чому?

Відповіді:


173

Коли порядок елементів у колекції не важливий, набори пропонують кращі показники пошуку предметів у колекції.

Причина полягає в тому, що набір використовує хеш-значення для пошуку елементів (наприклад, словник), тоді як масив повинен перебирати весь вміст, щоб знайти певний об'єкт.


9
log (1) vs log (n)
rohan-patel

25
@ rohan-patel Правильним є O (1) проти O (n)
Мансуров Руслан

1
Якщо замовлено: O (1) vs O (logn), оскільки застосовується двійковий пошук. Якщо не впорядковано, то O (1) проти O (n)
baskInEminence

180

Зображення з Документації Apple дуже добре описує це:

Колекції Objective-C

Array- впорядкована (порядок підтримується при додаванні) послідовності елементів

[array addObject:@1];
[array addObject:@2];
[array addObject:@3];
[array addObject:@4];
[array addObject:@6];
[array addObject:@4];
[array addObject:@1];
[array addObject:@2];

[1, 2, 3, 4, 6, 4, 1, 2]

Setце чіткий (без дублікатів), не упорядкований список елементів

[set addObject:@1];
[set addObject:@2];
[set addObject:@3];
[set addObject:@4];
[set addObject:@6];
[set addObject:@4];
[set addObject:@1];
[set addObject:@2];

[1, 2, 6, 4, 3]

2
У вашому прикладі ви додаєте примітиви до масиву та набору. Це неможливо, оскільки вони можуть містити лише об'єкти.
FreeAsInBeer

10
Дякуємо за вашу редакцію @Zaheer, але вона фактично була недійсною. Я не додавав примітивів. Я додав літерали.
Джеймс Вебстер

Чудове пояснення :) +1 :)
Карун

1
Любіть своє пояснення! +1 для цього
заколот

66

Найкраща відповідь на це - власна документація Apple .

введіть тут опис зображення

Основна відмінність полягає в тому, що NSArrayдля замовленої колекції таNSSet для колекції, .

Є кілька статей, які розповідають про різницю швидкості між цими двома, як ця . Якщо ви повторюєте невпорядковану колекцію, NSSetце чудово. Однак у багатьох випадках вам потрібно робити речі, які тільки NSArrayвміє робити, тому ви жертвуєте швидкістю для цих здібностей.

NSSet

  • Переважно отримуйте доступ до елементів порівняння
  • Без упорядкування
  • Не допускає дублікатів

NSArray

  • Може отримати доступ до елементів за індексом
  • Упорядковано
  • Дозволяє дублікати

Це все, що насправді є! Дайте мені знати, якщо це допомагає.


Не потрібно завжди жертвувати NSSetзаради індексації. Для одних і тих же даних прийнято використовувати дві різні структури даних. Або ви будуєте та індексуєте цей масив :) Але тоді краще використовувати БД, в якій реалізовано alredy.
Султан

"Побудувати індекс на цьому масиві". Ви не можете зробити індекс на NSSet. Є багато різних технік, якими ви можете скористатися. І якщо вам потрібно принести жертви в БОЛЬНУ пам'ять і потужність обробки, то ви робите це неправильно.
Султан

Оскільки питання про NSSetі NSArray, моя відповідь точна і повна. Так, ви можете створювати інші структури даних, але я лише порівнюю ці дві.
woz

Я підтримав, але ваша відповідь неправильна, коли ви говорите про жертви. Якщо вам потрібні певні функціональні можливості NSArrayта певна функціональність NSSet, правильна відповідь - це не "використання NSArrayта жертвоприношення". Відповідь - поєднати обидва або використовувати іншу структуру даних.
Султан

Я б сказав, що головна відмінність полягає в унікальних об'єктах, де масив може мати дублікати. Аспект порядку є другорядним для цього факту.
злочин

12

NSOrderedSet доступний в iOS 5+, тому головна відмінність полягає в тому, чи потрібно дублювати об'єкти в структурі даних.


9

NSArray :

  1. Замовлено збір даних
  2. Дозволяє дублікати
  3. Це об'єкт типу колекції

NSSet :

  1. Неупорядкований збір даних
  2. Не допускає дублікатів
  3. Це також об'єкт типу колекції

7

Масив використовується для доступу до елементів за їх індексом. Будь-який елемент можна вставити в масив кілька разів. Масиви підтримують порядок їх елементів.

Набір використовується в основному лише для перевірки, чи є предмет у колекції чи ні. Елементи не мають поняття порядку чи індексації. Ви не можете мати предмет у наборі двічі.

Якщо масив хоче перевірити, чи містить він елемент, він повинен перевірити всі його елементи. Набори розроблені для використання більш швидких алгоритмів.

Ви можете уявити набір як словник без значень.

Зауважте, що масив і набір - не єдині структури даних. Є й інші, наприклад, черга, стек, купа, купа Фібоначчі. Я рекомендую прочитати книгу про алгоритми та структури даних.

Додаткову інформацію див. У wikipedia .


Насправді масив потрібно перевірити лише до того моменту, як знайдений елемент. Якщо елемент є в масиві, дуже рідко буде потрібно перевіряти кожен елемент.
FreeAsInBeer

Так, як ви говорите "якщо елемент є в масиві". Якщо ви цього очікуєте, вам не доведеться перевіряти, є він чи ні. Складність containsоперації така O(n). Кількість порівнянь, коли їх немає в масиві n. Середня кількість порівнянь, коли об’єкт знаходиться в масиві, є n/2. Навіть якщо об’єкт знайдений, вистава жахлива.
Султан

Продуктивність була б жахливою лише з великим масивом. Якщо ви знали, що масив може стати досить великим, то є способи, які ви могли б покращити продуктивність масиву, наприклад, використовуючи масив масивів.
FreeAsInBeer

Якщо операція рівності дорога, ви побачите різницю навіть у масивах з 3 елементами. І така ж поведінка, як у великого масиву, може статися, коли ви багато разів повторите операцію (наприклад, використовуйте операцію в циклі "для"). Ви чули про амортизовану складність? Складність все ще лінійна, а продуктивність жахлива порівняно з набором (як правило, з постійною складністю).
Султан

Очевидно, що буде різниця, я просто констатую, що велика нотація експоненціальна; з невеликими масивами різниця буде незначною. Крім того, NSArrays мають інші переваги швидкості порівняно з NSSets. Як завжди, це компроміс.
FreeAsInBeer

5
NSArray *Arr;
NSSet *Nset;

Arr=[NSArray arrayWithObjects:@"1",@"2",@"3",@"4",@"2",@"1", nil];
Nset=[NSSet setWithObjects:@"1",@"2",@"3",@"3",@"5",@"5", nil];

NSLog(@"%@",Arr);
NSLog(@"%@",Nset);

масив

2015-12-04 11: 05: 40.935 [598: 15730] (1, 2, 3, 4, 2, 1)

набір

2015-12-04 11: 05: 43,362 [598: 15730] {(3, 1, 2, 5)}


4

Основні відмінності вже наведені в інших відповідях.

Я хотів би лише зазначити, що через те, як реалізуються набори та словники (тобто використовуються хеші), слід бути обережним, щоб не використовувати змінні об’єкти для клавіш.

Якщо ключ мутований, хеш (ймовірно) також зміниться, вказуючи на інший індекс / відро в хеш-таблиці. Вихідне значення не буде видалено, і воно буде фактично враховано при перерахуванні або запитуванні структури про її розмір / кількість.

Це може призвести до появи справді важких помилок.


3

Тут ви можете знайти досить ретельне порівняння структур NSArrayта NSSetданих.

Короткі висновки:

Так, NSArray швидше, ніж NSSet, просто утримуючи та повторюючи. Всього 50% швидше для побудови і так само 500% швидше для ітерації. Урок: якщо вам потрібно лише повторити вміст, не використовуйте NSSet.

Звичайно, якщо вам потрібно протестувати на включення, працюйте наполегливо, щоб уникнути NSArray. Навіть якщо вам потрібна ітерація, і тестування включення, ви, ймовірно, все ж повинні вибрати NSSet. Якщо вам потрібно впорядкувати колекцію впорядкованою, а також перевірити на включення, тоді слід розглянути можливість збереження двох колекцій (NSArray та NSSet), кожна з яких містить однакові об'єкти.

NSDictionary будується повільніше, ніж NSMapTable - оскільки йому потрібно скопіювати ключові дані. Він компенсує це тим, що швидше шукати. Звичайно, обидва мають різні можливості, тому більшу частину часу це визначення слід проводити з інших факторів.


Хоча це теоретично може відповісти на питання, бажано було б сюди включити істотні частини відповіді та надати посилання для довідки.
Тунакі

2

Зазвичай ви використовуєте набір, коли швидкість доступу є суттєвою, а порядок не має значення , або визначається іншими способами (через дескриптор предиката або сортування). Наприклад, Core Data використовує набори, коли доступ до керованих об'єктів здійснюється через відношення до багатьох


1

Просто для додання трохи цього я використовую набір іноді просто для видалення дублікатів з масиву на зразок: -

NSMutableSet *set=[[NSMutableSet alloc]initWithArray:duplicateValueArray]; // will remove all the duplicate values
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.