Для фиксированного числа полей (3 в вашем примере), существует простой способ сделать это, который позволяет добавлять, удалять и запрашивать операции всего за O (1) времени. Он использует O (n) памяти, но с относительно большим постоянным коэффициентом; Это нормально, если у вас мало ограничений на память. Я напишу без указания языка программирования c, поскольку я не использую Swift.
Ведение словаря, в котором каждая комбинация полей, включая символы подстановки, сопоставляется с набором Element
объекты. Это, вероятно, проще всего описать на примере: предположим, что элементы:
X = (a=1, b=2, c=3)
Y = (a=1, b=3, c=4)
Z = (a=2, b=3, c=4)
Тогда ваш словарь выглядит так:
{
// just a
(1, nil, nil): {X, Y}, (2, nil, nil): {Z},
// just b
(nil, 2, nil): {X}, (nil, 3, nil): {Y, Z},
// just c
(nil, nil, 3): {X}, (nil, nil, 4): {Y, Z}}`.
// a and b
(1, 2, nil): {X}, (1, 3, nil): {Y}, (2, 3, nil): {Z},
// a and c
(1, nil, 3): {X}, (1, nil, 4): {Y}, (2, nil, 4): {Z},
// b and c
(nil, 2, 3): {X}, (nil, 3, 4): {Y, Z},
// a, b, c
(1, 2, 3): {X}, (1, 3, 4): {Y}, (2, 3, 4): {Z}
}
По сути, структура данных просто хранит ответ на каждый возможный запрос (кроме тех, которые не дают результатов).
Чтобы добавить или удалить элемент, необходимо обновить наборы, принадлежащие 2 ^ 3 - 1 = 7 ключей, и, возможно, добавить новый ключ с новым набором или удалить ключ. Если для словаря и наборов используются хеш-таблицы, все соответствующие операции словаря / набора занимают O (1) времени, а количество таких операций, которое необходимо выполнить, составляет O (1), поэтому добавление или удаление из структуры данных занимает O (1) раз.
Чтобы выполнить запрос по некоторой комбинации значений полей, просто найдите запрос в словаре и верните соответствующий набор (или верните неизменяемое представление).
Все это говорит о том, что только для 300 элементов стоит сравнить «наивное» решение, в котором вы просто сохраняете элементы в списке и проверяете весь список для каждого запроса. 300 не является большим числом, возможно, недостаточно большим, чтобы значение O (1) и O (n) имело значение. В зависимости от языка программирования другие детали, такие как прогнозирование ветвлений и кэш-память ЦП, могут оказывать большее влияние, чем теоретическая сложность Я бы рекомендовал сравнить оба варианта.