Подтвердить что ты не робот

Можно ли выполнить частичное совпадение строк в ключевой строке словаря?

У меня есть Dictionary<string, List<int>> в моем коде, который я использую следующим образом:

Key           Values  
2011-07-15    1, 2, 3
2011-07-20    4, 5, 6
2010-02-11    7, 8, 9

Мой код должен иметь возможность запрашивать все значения, соответствующие определенной подстроке в ключе. Например, если у меня была подстрока 2011-07, она должна возвращать значения {1, 2, 3, 4, 5, 6}. Подстрока 11 должна возвращать все идентификаторы из 1-9.

Может кто-нибудь порекомендовать кратчайший путь для достижения этого? Или предоставить лучшую структуру данных для извлечения этой информации?

4b9b3361

Ответ 1

Я бы сделал метод расширения:

public static class DictionaryExt
{
    public static IEnumerable<T> PartialMatch<T>(this Dictionary<string, T> dictionary, string partialKey)
    {
        // This, or use a RegEx or whatever.
        IEnumerable<string> fullMatchingKeys = 
            dictionary.Keys.Where(currentKey => currentKey.Contains(partialKey));

        List<T> returnedValues = new List<T>();

        foreach (string currentKey in fullMatchingKeys)
        {
            returnedValues.Add(dictionary[currentKey]);
        }

        return returnedValues;
    }
}

"Стоимость" добавления значений в словарь не изменится, но стоимость поиска будет выше, но только тогда, когда вы знаете, что вы собираетесь с частичным совпадением.

Btw, я уверен, что вы могли бы преобразовать это в одном выражении Lambda, но концепция осталась прежней.

Изменить. В вашем примере этот метод вернет 2 списка значений, но вы можете изменить их для объединения списков. Вот способ расширения, который вы могли бы сделать:

public static IEnumerable<T> PartialMatch<T>(
    this Dictionary<string, IEnumerable<T>> dictionary,
    string partialKey)
{
    // This, or use a RegEx or whatever.
    IEnumerable<string> fullMatchingKeys = 
        dictionary.Keys.Where(currentKey => currentKey.Contains(partialKey));

    List<T> returnedValues = new List<T>();

    foreach (string currentKey in fullMatchingKeys)
    {
        returnedValues.AddRange(dictionary[currentKey]);
    }

    return returnedValues;
}

Изменить 2. Подумайте об этом, вы также можете сделать его более общим. С помощью следующего метода расширения он будет работать с любым словарем, если вы предоставите comparer, которые проверяют, что вы подразумеваете под "частичным соответствием":

public static IEnumerable<TValue> PartialMatch<TKey, TValue>(
    this Dictionary<TKey, IEnumerable<TValue>> dictionary,
    TKey partialKey,
    Func<TKey, TKey, bool> comparer)
{
    // This, or use a RegEx or whatever.
    IEnumerable<TKey> fullMatchingKeys = 
        dictionary.Keys.Where(currentKey => comparer(partialKey, currentKey));

    List<TValue> returnedValues = new List<TValue>();

    foreach (TKey currentKey in fullMatchingKeys)
    {
        returnedValues.AddRange(dictionary[currentKey]);
    }

    return returnedValues;
}

Ответ 2

Вы ищете краткие ответы. Без фантазии индексирования на низкоуровневом тексте (о котором я не знаю каких-либо специализированных классов .Net), я думаю, что словарь по-прежнему остается вашим лучшим выбором. Запрос с чем-то вроде:

myDictionary.Where(КВП = > kvp.Key.Contains( "11" )) SelectMany (КВП = > kvp.Value);.

В любом случае вам нужно искать все ключи для обобщенной подстроки без какой-либо довольно крутой магии (не предоставленной .Net), поэтому LINQ не должен сильно причинять вам боль.

Ответ 3

Если словарь использует внутренние хэши, вам не повезло, так как аналогичные строки дают разные хэши. Я только что реализовал решение этого требования в выходные дни на С, тест на собеседование/домашнее задание. Я использовал отсортированный массив в качестве базовой структуры - дорогие вставки, но быстрый поиск (с использованием двоичного поиска). Чтобы найти все записи с ключом, начинающимся с префикса, я бы нашел 1-й, а затем просто следующий, следующий... Для общей подстроки, т.е. Не только префикса, мое решение не сработало. На данный момент я не знаю, что предложить для поиска "общей подстроки".

Ответ 4

У вас может быть три словаря. Год, месяц, день.

Обратите внимание, что при добавлении элементов в три словаря вы не дублируете элементы.

Когда вы вытаскиваете элементы с помощью двух клавиш, вы можете использовать метод расширения LINQ Intersect(), чтобы получить элементы, соответствующие обеим клавишам (используйте Intersect для двух наборов результатов).

Предостережение, делать это таким образом не приведет к быстрому выполнению кода.

Ответ 5

Кратким способом было бы использовать Multivalue Map.

Например:

Dictionary<string, Dictionary<string, List<int>>

почему вы не храните 2011-07 как ключ и 15 для внутреннего словарного ключа и 1,2,3 в качестве значений.

map [ "2011-07" ] [ "15" ] = {1,2,3};

если вы хотите просто 2011-07, вы можете получить все в пределах другого словаря путем обхода.

map["2011-07"]//вернул бы u 1,2,3,4,5,6

и если вы хотите перейти к определенному дню, 2011-07-15, это вернет u только 1,2,3

foreach(var element in map["2011-07"]){

     var values = element.values; // and you can append them to a list.

}

если вам понадобится год/месяц/день, вам понадобятся многоуровневые словари. или вы можете использовать Дерево.