как проверить что в словаре что-то есть?
static void Main(string[] args)
{
Dictionary<string, Dictionary<string, string>> dict = new Dictionary<string, Dictionary<string, string>>();
if (dict)
{
Console.WriteLine("1");
}
}
Есть словарь со вложенным словарем. Как написать условие, которое бы сразу проверяло наличие данных в словаре и срабатывало бы, если в словарях что-то есть, и не срабатывало, если в них ничего нет?
Ответы (2 шт):
Проверить наличие ключа в словаре:
public bool ContainsKey(TKey key);
Пример:
if (dict.ContainsKey(5))
{
Console.WriteLine("dict[5] существует");
}
Получить значение по ключу в словаре, если ключ в нём содержится:
public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value);
Данный метод нужен что бы не делать поиск ключа дважды когда тебе надо его получить, но ты не уверен в его существовании.
Пример использования:
if (dict.TryGetValue(6, out var value))
{
Console.WriteLine($"dict[6] == {value}");
}
else
{
Console.WriteLine("dict[6] не существует");
}
Проверить наличие значения в словаре:
public bool ContainsValue(TValue value);
Отлично работает если TValue является типом значений (например int, string, struct и другие примитивные типы)
Таким образом для
Dict<string, int> dict { {"key", 5} };
dict.ContainsValue(5);
Вернёт true
Однако с ссылочными типами (такие как наши объекты и т. п.) есть нюанс
ContainsValue(TValue value) для ссылочных типов использует value.Equals метод для поиска нужного объекта.
А по умолчанию (для object и всего, что его наследует) он сравнивает ссылки на этот объект. Таким образом для класса
class Test
{
public int v = 5;
}
var dict = new Dictionary<int, Test>()
{
{5, new Test() {v = 5 } },
};
код
if (dict.ContainsValue(dict[5]))
Console.WriteLine("true");
else
Console.WriteLine("false")
выведет true, ведь dict[5] и dict[5] это один и тот же объект
Однако этот код
if (dict.ContainsValue(new Test() { v = 5 }))
Console.WriteLine("true");
else
Console.WriteLine("false");
выведет false, ведь new создаёт новый объект.
P. S.: С типами значений, даже при прописывании new всё работать будет, т. к. так устроена память
Если же мы хотим, что бы код выше заработал нам необходимо переопределить метод Equals:
class Test
{
public int v = 5;
public override bool Equals(object? obj)
{
if (obj is Test test) // Если тип второго объекта такой же
return test.v == v; // то возвращаем true, если v совпадают
return base.Equals(obj); // иначе стандартная проверка
}
}
Теперь код
if (dict.ContainsValue(new Test() { v = 5 }))
Console.WriteLine("Test {v=5} существует");
сработает
Получить ключ/значение элемента с помощью linq и своего компаратора:
Мы так же можем использовать linq методы для поиска. Таким образом мы можем найти значение используя не конкретное значение, а компаратор. Допустим у нас есть словарь:
var dict = new Dictionary<string, Dictionary<string, string>>()
{
{
"key1",
new()
{
{ "kkey1", "ok!" }
}
},
{
"key2",
new()
{
{ "kkey2", "ok2!" }
}
}
};
Что эквивалентно этому в json:
{
key1: {
kkey1: 'ok!'
},
key2: {
kkey2: 'ok2!'
}
}
И мы хотим получить такой ключ внешнего словаря, у которого во внутреннем словаре имеется значение ok2! (в нашем случае это key2)
Это можно реализовать так:
// Ищем первое вхождение, у которого у значения имеется значение ok2!
var key = dict.First(e => e.Value.ContainsValue("ok2!")).Key;
Сюда вы можете поставить любую функцию, которая будет проверять значение (а может даже и ключ).
Вообще linq имба, вот ещё пример, где мы очищаем все вхождения, где ключ == значение:
Тут так же можно увидеть, как преобразовать IEnumerable<KeyValuePair<...>> в Dictionary<...>
var dict = new Dictionary<string, string>()
{
{ "a", "a" },
{ "b", "c" }
};
var filteredDict = dict.Where(e => e.Key != e.Value).ToDictionary(v => v.Key, v => v.Value);
// filteredDict == {b: "c"}
Если нужно узнать, содержит ли словарь элементы, можно использовать его свойство Count
if (dict.Count > 0) {
// словарь не пуст - содержит элемент(ы)
} else {
// словарь пуст - не содержит элементов
}