Удаление ключа в словаре

Как мне удалить указанный ключ в Словаре на основе следующего условия?

foreach (var kvp in dict)
            {
                if (kvp.Key.Contains('/'))
                {
                    //delete the key
                }
            }

person Arianule    schedule 13.02.2013    source источник
comment
Вы не можете изменить коллекцию, которую вы повторяете в foreach.   -  person Igoy    schedule 13.02.2013
comment
Вы хотите удалить только ключ или всю запись?   -  person jAC    schedule 13.02.2013
comment
Я хочу удалить всю запись   -  person Arianule    schedule 13.02.2013
comment
Разве вы не можете использовать dict.Delete (dicEntry).   -  person fhnaseer    schedule 13.02.2013
comment
@Faisal: он не может, потому что не знает точного ключа, который нужно удалить   -  person Francesco Baruchelli    schedule 13.02.2013


Ответы (6)


РЕДАКТИРОВАТЬ: Как сказано в других ответах ниже, в приведенном ниже коде важно вызвать ToList (). Это создаст копию dict, которую вы сможете перебирать, удаляя элементы из dict, не изменяя коллекцию, которую вы повторяете.

Вы можете сделать это, используя что-то вроде

    dict.ToList().ForEach(a => { if (a.Key.Contains('/') dict.Remove(a.Key); });
person Ash    schedule 13.02.2013
comment
Для будущих посетителей может быть полезно иметь не только код для копирования и вставки, но и объяснение того, как это решает вопрос. - person O. R. Mapper; 13.02.2013
comment
Я бы подумал, что создание копии всего словаря только для того, чтобы удалить из него один элемент, неоптимально ... Я предлагаю избежать этого и использовать ответ Дэниела Хилгарта ниже (или мой, если вы хотите удалить только один элемент). - person Matthew Watson; 13.02.2013
comment
@MatthewWatson: Действительно, приведенное ниже решение Дэниела, вероятно, лучше в этом отношении. - person O. R. Mapper; 13.02.2013

Вы бы сделали это так:

foreach(var keyToDelete in dict.Keys.Where(x => x.Contains('/')).ToList())
    dict.Remove(keyToDelete);

Здесь важен вызов ToList() после Where. Это поместит все ключи, которые следует удалить, в новый список, который вы можете перебирать.
Если вы попробуете этот код без ToList(), вы получите InvalidOperationException:

Коллекция была изменена; операция перечисления может не выполняться.

Обратите внимание, что этот код более эффективен, чем принятый в настоящее время ответ. Он копирует только те ключи, которые необходимо удалить, а не весь словарь.

person Daniel Hilgarth    schedule 13.02.2013
comment
ToArray может иметь немного меньше накладных расходов, чем ToList, если OP не собирается делать что-либо с элементами, кроме повторения по ним один раз позже. - person O. R. Mapper; 13.02.2013
comment
@ O.R.Mapper: Может, есть? :) Есть ссылки на это? - person Daniel Hilgarth; 13.02.2013
comment
На самом деле имеет как минимум небольшое количество (которое остается небольшим, если мы предполагаем, что Capacity не настроен ни на что необоснованное). - person O. R. Mapper; 13.02.2013
comment
@ O.R.Mapper: Спасибо за ссылку. Разница настолько незначительна, что я продолжу использовать ToList() :) - person Daniel Hilgarth; 13.02.2013

Проблема в том, что вы не можете изменить коллекцию, перебирая ее элементы. Решение состоит в том, чтобы поместить ключи для удаления в другую коллекцию, а затем перебрать ее, чтобы удалить элементы. Это то, что делает ответ Даниила.

Если вы не можете / не хотите использовать LINQ, вы можете сделать это следующим образом:

List<YourKeyType> toRemove = new List<YourKeyType>();
foreach (var kvp in dict)
{
    if (kvp.Key.Contains('/'))
        toRemove.Add(kvp.Key);
}
foreach (var aKey in toRemove)
    dict.Remove(aKey);
person Francesco Baruchelli    schedule 13.02.2013
comment
Ваши ответы и ответы Дэниела Хилгарта - безусловно, самый эффективный ответ для удаления нескольких ключей. Честно говоря, я нахожу все ответы, связанные с копированием словаря, весьма тревожными. - person Matthew Watson; 13.02.2013

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

dict = dict.Where(kvp => !kvp.Key.Contains('/'))
           .ToDictionary(kvp => kvp.Key, kvp => kvp.Value);

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

person Christoffer    schedule 13.02.2013

Я понимаю, что это уже помечено как ответ, но я думаю, что если вы хотите удалить только один ключ из словаря, где максимальный размер не указан, создание копии ВСЕГО словаря только для удаления одного ключа НЕ является хорошим решением !

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

foreach (var kvp in dict)
{
    if (kvp.Key.Contains('/'))
    {
        dict.Remove(kvp.Key);
        break;
    }
}

Копии словарей целиком не требуются!

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

(На самом деле, я рекомендую вам просто использовать ответ Дэниела, но я оставлю это здесь в качестве примера без использования Linq.)

person Matthew Watson    schedule 13.02.2013

Foreach, вероятно, вызовет исключение. Попробуйте вместо этого использовать for.

Для удаления используйте метод Remove.

person petko_stankoski    schedule 13.02.2013
comment
Как бы вы использовали for в словаре? - person O. R. Mapper; 13.02.2013
comment
@ O.R.Mapper for (int i = 0; i ‹dict.Count; i ++) {// dict [key]; } - person petko_stankoski; 13.02.2013
comment
И как именно мы перейдем от i к key? - person O. R. Mapper; 13.02.2013