С ограничением на то, что условие может быть «чем угодно», вы ограничены сканированием всего списка и применением условия.
Если в условии условия есть ограничения, то вы можете посмотреть на организацию данных для более эффективной обработки запросов.
Например, пример кода со словарем "byFirstLetter" вообще не помогает с запросом конца-с-нуля.
Итак, все сводится к тому, какие запросы вы хотите выполнить к этим данным.
В базах данных эта проблема является бременем "оптимизатора запросов". В типичной базе данных, если у вас есть база данных без индексов, очевидно, что каждый запрос будет сканированием таблицы. Когда вы добавляете индексы в таблицу, оптимизатор может использовать эти данные для составления более сложных планов запросов, чтобы лучше добраться до данных. По сути, это проблема, которую вы описываете.
Если у вас есть более конкретное подмножество типов запросов, вы можете принять лучшее решение о том, какая структура лучше. Также вам нужно учитывать объем данных. Если у вас есть список из 10 элементов, каждый размером менее 100 байт, сканирование всего может оказаться самым быстрым, что вы можете сделать, поскольку у вас такой маленький объем данных. Очевидно, что это не масштабируется до элементов 1M, но даже умные методы доступа влекут за собой затраты на настройку, обслуживание (например, обслуживание индекса) и память.
РЕДАКТИРОВАТЬ , на основании комментария
Если это автозаполнение, если данные статические, то сортируйте их и используйте двоичный поиск. Вы действительно не будете быстрее, чем это.
Если данные динамические, сохраните их в сбалансированном дереве и выполните поиск по ним. По сути, это бинарный поиск, позволяющий добавлять данные случайным образом.
Что-то еще является специализацией в этих понятиях.