Структура MRU с фиксированным количеством элементов, автоматически адаптирующаяся к запросам LINQ.C#

Место общения программистов C#
Ответить
Anonymous
 Структура MRU с фиксированным количеством элементов, автоматически адаптирующаяся к запросам LINQ.

Сообщение Anonymous »

У меня есть папка, содержащая огромное количество файлов во многих подпапках, и я хочу выбрать файлы с именем, соответствующим любому из заданного списка шаблонов (регулярных выражений). Мои регулярные выражения сложны, я не могу объединить их в одно. Моя проблема в том, что сопоставление всех имен файлов со всеми шаблонами требует времени, и я хочу ускорить процесс. Сейчас мой код выглядит так:

Код: Выделить всё

Regex[] regexes = [new(@"^[a-f]+$"), new(@"^[g-l]+$"), new(@"^[m-r]+$"), new(@"^[s-x]+$")];
string[] matchedPaths = Directory
.EnumerateFiles(@"C:\Files", "*.*", SearchOption.AllDirectories)
.Where(path =>
{
string name = Path.GetFileNameWithoutExtension(path);
return regexes.Any(regex => regex.IsMatch(name));
})
.ToArray();
Реальные шаблоны намного сложнее, я просто показываю пример.
Моя идея решить эту проблему связана с тем фактом, что в каждой папке обычно содержатся в основном файлы, соответствующие одному конкретному шаблону. Поэтому, если я начну сопоставлять с шаблоном, который соответствовал предыдущему файлу, есть вероятность, что он также будет соответствовать тому же шаблону (или не будет соответствовать никакому шаблону). Поэтому вместо того, чтобы помещать регулярные выражения в стандартный массив, я подумываю о том, чтобы поместить их в структуру MRU (самые недавно использованные), которая активно переупорядочивает свое содержимое после каждой успешной операции Any LINQ. Если мне удастся реализовать эту структуру, все, что мне придется изменить в своем коде, — это определение регулярных выражений:

Код: Выделить всё

MruArray regexes = new(new(@"^[a-f]+$"), new(@"^[g-l]+$"), ...
API этой структуры может быть чем-то простым:

Код: Выделить всё

class MruArray : IEnumerable
{
public MruArray(params T[] items);
public IEnumerator GetEnumerator();
}
...и должен вести себя следующим образом:

Код: Выделить всё

MruArray mru = new(1, 2, 3, 4, 5, 6, 7, 8);
_ = mru.Any(x => x == 5);
Console.WriteLine(String.Join(", ", mru));
_ = mru.Any(x => x == 3);
Console.WriteLine(String.Join(", ", mru));
_ = mru.Any(x => x == 8);
Console.WriteLine(String.Join(", ", mru));
Вывод:

Код: Выделить всё

5, 1, 2, 3, 4, 6, 7, 8
3, 5, 1, 2, 4, 6, 7, 8
8, 3, 5, 1, 2, 4, 6, 7
  • Когда Any находит совпадение в последовательности, последний перечисляемый элемент должен стать первым.
  • Когда Any перечисляет всю последовательность, не находя совпадений, последовательность должна оставаться неизменной.
Как реализовать эту структуру?
Потокобезопасность нежелательна. Структура не должна быть безопасной для многопоточности без синхронизации.
Примечание: В центре внимания вопроса — реализация структуры данных MRU, а не другие идеи по ускорению поиска в папке.
Изменить: Выше я представил упрощенную версию своей проблемы. На самом деле меня интересуют не только файлы, соответствующие шаблону. Меня интересуют подвыражения внутри шаблонов, а затем группирую файлы на основе этих подвыражений. Итак, мой фактический код выглядит примерно так:

Код: Выделить всё

KeyValuePair[] groups = Directory
.EnumerateFiles(@"C:\Files", "*.*", SearchOption.AllDirectories)
.Select(p => Path.GetFileNameWithoutExtension(p))
.Select(n => regexes.Select(r => r.Match(n)).FirstOrDefault(m => m.Success))
.Where(m => m is not null)
.Select(m => m.Groups["Name"].Value)
.CountBy(x => x)
.OrderBy(p => p.Key, StringComparer.OrdinalIgnoreCase)
.ToArray();
Эти детали не должны отвлекать от сути вопроса, а именно от запрошенной реализации структуры данных MRU.

Подробнее здесь: https://stackoverflow.com/questions/798 ... -linq-quer
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C#»