O que acontecerá com a pesquisa de <int, int> do dicionário C # se a chave não existir?

121

Tentei verificar se há nulo, mas o compilador avisa que essa condição nunca ocorrerá. O que devo procurar?

Deltanovember
fonte

Respostas:

196

Supondo que você deseja obter o valor se a chave não existir, use Dictionary<TKey, TValue>.TryGetValue:

int value;
if (dictionary.TryGetValue(key, out value))
{
    // Key was in dictionary; "value" contains corresponding value
} 
else 
{
    // Key wasn't in dictionary; "value" is now 0
}

(Usar ContainsKeye, em seguida, o indexador faz com que ele procure a chave duas vezes, o que é bastante inútil.)

Observe que mesmo se você estivesse usando tipos de referência, a verificação de null não funcionaria - o indexador de Dictionary<,>lançará uma exceção se você solicitar uma chave ausente, em vez de retornar null. (Esta é uma grande diferença entre Dictionary<,>e Hashtable.)

Jon Skeet
fonte
@JonSkeet O TryGetValue também não está fazendo uma pesquisa dupla ( conforme declarado no corpo desta pergunta )?
nawfal
5
@nawfal: Não vejo nenhuma indicação de que essa pergunta afirme isso. Diz que está fazendo mais trabalho do que ContainsKey, o que é verdade, porque também precisa extrair valor. Não está fazendo duas pesquisas embora.
Jon Skeet
Ingenuamente, eu esperava nulo, mas para Dictionary <TKey, enum>, isso retorna o equivalente "0" no enum.
Jess de
23

O Dicionário lança uma KeyNotFoundexceção caso o dicionário não contenha sua chave.

Como sugerido, ContainsKeyé a precaução adequada. TryGetValuetambém é eficaz.

Isso permite que o dicionário armazene um valor nulo de forma mais eficaz. Sem ele se comportar dessa maneira, a verificação de um resultado nulo do operador [] indicaria um valor nulo OU a não existência da chave de entrada, o que não é bom.

antik
fonte
Informações adicionais podem ser encontradas em MSDN: msdn.microsoft.com/en-gb/library/9tee9ht2.aspx
cibernético em
10

Se você está apenas verificando antes de tentar adicionar um novo valor, use o ContainsKeymétodo:

if (!openWith.ContainsKey("ht"))
{
    openWith.Add("ht", "hypertrm.exe");
}

Se você está verificando se o valor existe, use o TryGetValuemétodo descrito na resposta de Jon Skeet.

ChrisF
fonte
8
TryGet é melhor
Ruben Bartelink
2
Porque você está resolvendo a pesquisa de chave por meio da tabela de hash duas vezes se você imediatamente obter após o Contains. O Wintellect PowerCollections também possui GetValueElseAddmétodos para os quais você fornece um valor (ou a Func<TValue>) para também salvar a resolução no Insert se você for adicionar se não estiver lá. Eu acho que o motivo pelo qual não foi incluído nas bibliotecas .NET é porque o caminho Add é menos frequente se você o estiver usando em um estilo de cache]
Ruben Bartelink
@rub: Acho que depende do propósito do código. Se você quiser usar o valor, eu concordo que TryGetValueseria melhor, mas se você quiser verificar se o dicionário contém a chave para evitar adições duplicadas, eu diria que ContainsKeyé tão bom (se não melhor).
Fredrik Mörk
@Fredrik: Se você quer apenas fazer uma verificação de contenção, então sim, vale a pena usar ContainsKey. Observe que esse não é o caso no código de amostra desta resposta.
Jon Skeet
@Jon: verdade, na verdade não percebi que o valor agregado foi obtido imediatamente após ter sido adicionado.
Fredrik Mörk
3

Você deve verificar Dictionary.ContainsKey (int key) antes de tentar extrair o valor.

Dictionary<int, int> myDictionary = new Dictionary<int, int>();
myDictionary.Add(2,4);
myDictionary.Add(3,5);

int keyToFind = 7;
if(myDictionary.ContainsKey(keyToFind))
{
    myValueLookup = myDictionay[keyToFind];
    // do work...
}
else
{
    // the key doesn't exist.
}
ZombieSheep
fonte
2
Por que você quer fazer a pesquisa duas vezes?
Jon Skeet
2
@mookid: Não na minha opinião. A ideia é tentar procurar a chave e tomar um curso de ação se ela for encontrada e outro curso de ação caso contrário, certo?
Jon Skeet
3
@Jon - Honestamente? Porque eu não sabia TryGetValue. Felizmente, eu sei agora, então saberei no futuro. Vou deixar esta resposta intacta, embora porque a discussão seja valiosa.
ZombieSheep
@Jon Skeet - É por isso que estou aqui. :)
ZombieSheep
@JonSkeet Porque antes do C # 7, você não podia usar TryGetValueem uma expressão lambda. Embora isso me faça pensar que uma nova extensão para C # seria um catchoperador semelhante ao nulloperador coalescente.
NetMage de
1

Uma classe auxiliar é útil:

public static class DictionaryHelper
{
    public static TVal Get<TKey, TVal>(this Dictionary<TKey, TVal> dictionary, TKey key, TVal defaultVal = default(TVal))
    {
        TVal val;
        if( dictionary.TryGetValue(key, out val) )
        {
            return val;
        }
        return defaultVal;
    }
}
Sheamus
fonte
Às vezes me pergunto por que isso não é adicionado à biblioteca padrão. Quase todas as linguagens que usam hashmaps retornam null se não houver entrada, não uma exceção estranha. Um item que não existe em seu dicionário não é um comportamento excepcional.
Adam Hess
@AdamHess - é por isso que você tem Hashtable () em c # ... infelizmente, suas chaves são
embaladas
0

ContainsKey é o que você está procurando.


fonte
0

Você provavelmente deve usar:

if(myDictionary.ContainsKey(someInt))
{
  // do something
}

O motivo pelo qual você não pode verificar se há nulo é que a chave aqui é um tipo de valor.

Razzie
fonte
1
O tipo do valor é um tanto irrelevante, pois a verificação de null não teria o efeito desejado.
Jon Skeet
@Johannes, a solução de Jon é obviamente muito melhor, mas o autor da pergunta afirmou que ele verificou se a chave existe, e é um Dicionário <int, int>, então a chave também é um tipo de valor aqui.
Razzie
0
int result= YourDictionaryName.TryGetValue(key, out int value) ? YourDictionaryName[key] : 0;

Se a chave estiver presente no dicionário, ele retorna o valor da chave, caso contrário, retorna 0.

Espero que este código ajude você.

Nitika Chopra
fonte
1
Se a chave existir, este código pesquisará duas vezes. TryGetValueé o suficiente, use em valuevez deresult
Mathieu VIALES
0

Considere a opção de encapsular este dicionário específico e fornecer um método para retornar o valor para essa chave:

public static class NumbersAdapter
{
    private static readonly Dictionary<string, string> Mapping = new Dictionary<string, string>
    {
        ["1"] = "One",
        ["2"] = "Two",
        ["3"] = "Three"
    };

    public static string GetValue(string key)
    {
        return Mapping.ContainsKey(key) ? Mapping[key] : key;
    }
}

Então você pode gerenciar o comportamento deste dicionário.

Por exemplo aqui: se o dicionário não tem a chave, ele retorna a chave que você passa por parâmetro.

pablocom96
fonte