Удалите все элементы, соответствующие условию в IDictionary

Я пытаюсь удалить все элементы в объекте IDictionary, соответствующие условию.

Например. IDictionary содержит набор ключей и соответствующих значений (скажем, 80 объектов). Ключи - это строки, значения могут быть разных типов (подумайте об извлечении метаданных из файла wtv с помощью directshow).

Некоторые клавиши содержат текст «большой палец», например thumbsize, startthumbdate и т. д. Я хочу удалить все объекты из IDictionary, ключи которых содержат слово thumb.

Единственный способ, который я здесь вижу, - это вручную указать имя каждого ключа с помощью метода .Remove.

Есть ли способ получить все объекты, ключи которых содержат слово thumb, и удалить их из объекта IDictionary.

Код выглядит так:

IDictionary sourceAttrs = editor.GetAttributes();

GetAttributes определяется как:

public abstract IDictionary GetAttributes();

У меня нет контроля над GetAttributes, он возвращает объект IDictionary, я знаю содержимое только по его просмотру во время отладки. (вероятно, HashTable)

ОБНОВЛЕНИЕ: окончательный ответ благодаря Тиму:

sourceAttrs = sourceAttrs.Keys.Cast<string>()
                 .Where(key => key.IndexOf("thumb", StringComparison.CurrentCultureIgnoreCase) == -1)
                 .ToDictionary(key => key, key => sourceAttrs[key]);

person rboy    schedule 10.05.2014    source источник
comment
Что это за настоящий тип? Если это действительно общий словарный запас, вы можете просто использовать его. Вы можете попробовать применить его с помощью оператора as. Например: var dict = sourceAttrs as Dictionary<string, object>. Нулевой, если приведение не работает.   -  person Tim Schmelter    schedule 11.05.2014
comment
не знаю, похоже на хеш-таблицу с ‹строка, объект›   -  person rboy    schedule 11.05.2014
comment
Пожалуйста, не включайте информацию о языке, который используется в заголовке вопроса, если без него это не имело бы смысла. Этой цели служат теги.   -  person Ondrej Janacek    schedule 11.05.2014
comment
Получил, спасибо за обращение в будущем   -  person rboy    schedule 11.05.2014


Ответы (2)


Итак, вы хотите удалить все записи, в которых ключ содержит подстроку.

Вы можете использовать LINQ, сохранив все, что не его содержит:

dict = dict
  .Where(kv => !kv.Key.Contains("thumb"))
  .ToDictionary(kv => kv.Key, kv => kv.Value);

Если вам нужно сравнение без учета регистра, вы можете использовать IndexOf:

dict = dict
  .Where(kv => kv.Key.IndexOf("thumb", StringComparison.CurrentCultureIgnoreCase) == -1)
  .ToDictionary(kv => kv.Key, kv => kv.Value);

Обновите в соответствии с вашим изменением не общего характера:

Если это неуниверсальный словарь, такой как HashTable, вы не можете использовать LINQ напрямую, но если вы знаете, что ключ - это string, вы можете использовать следующий запрос:

// sample IDictionary with an old Hashtable
System.Collections.IDictionary sourceAttrs = new System.Collections.Hashtable
{ 
    {"athumB", "foo1"},
    {"other", "foo2"}
};

Dictionary<string, object> newGenericDict = sourceAttrs.Keys.Cast<string>()
    .Where(key => !key.Contains("thumb"))
    .ToDictionary(key => key, key => sourceAttrs[key]);

Но, возможно, это на самом деле общий Dictionary, вы можете попробовать выполнить приведение с помощью оператора as:

var dict = sourceAttrs as Dictionary<string, object>;

Нулевой, если приведение не сработало.

person Tim Schmelter    schedule 10.05.2014
comment
Я не знаю, где метод Where с объектом IDictionary (я включил system.linq и использовал клиентскую структуру .net4) - person rboy; 11.05.2014
comment
@rboy: вам нужен общий словарь, например IDictionary<string, object> dict = new Dictionary<string, object>() - person Tim Schmelter; 11.05.2014
comment
Я отредактирую вопрос, чтобы добавить больше деталей, я не знаю, что содержит IDictionary. Мне его возвращает абстрактный интерфейс. - person rboy; 11.05.2014
comment
Спасибо, а для большого пальца регистр не учитывается? - person rboy; 11.05.2014
comment
Почему бы не использовать: sourceAttrs = sourceAttrs.Keys.Cast ‹string› () .Where (key = ›! Key.ToLower (). Contains (thumb)) .ToDictionary (key =› key, key = ›sourceAttrs [key]) ; - person rboy; 11.05.2014
comment
Используйте IndexOf с соответствующим StringComparison, как показано выше, это более эффективно и также не имеет проблем с такими языками, как турецкий. - person Tim Schmelter; 11.05.2014
comment
Спасибо, я обновил ответ, дайте мне знать, если это правильный ответ. - person rboy; 11.05.2014

Если ваш словарь доступен только для чтения, вам нужно будет удалить элементы один за другим, и в этом случае вы также можете использовать LINQ:

dict
  .Keys
  .Where(p => p.Contains("thumb"))
  .ToList
  .ForEach(p => dict.Remove(p);

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

Если ваш словарь не предназначен только для чтения и эффективность вызывает беспокойство, вам лучше воспользоваться советами Тима.

person Ama    schedule 18.09.2019