2013-05-31 16 views
9

Non riesco a ottenere la chiave specificando un valore. Qual è il modo migliore per ottenerlo?Ottieni la chiave dal valore - Dizionario <stringa, Lista <string>>

var st1= new List<string> { "NY", "CT", "ME" }; 
var st2= new List<string> { "KY", "TN", "SC" }; 
var st3= new List<string> { "TX", "OK", "MO" }; 
var statesToEmailDictionary = new Dictionary<string, List<string>>(); 
statesToEmailDictionary.Add("[email protected]", st1); 
statesToEmailDictionary.Add("[email protected]", st2); 
statesToEmailDictionary.Add("[email protected]", st3); 

var emailAdd = statesToEmailDictionary.FirstOrDefault(x => x.Value.Where(y => y.Contains(state))).Key; 

risposta

17

Il valore restituito da FirstOrDefault sarà un KeyValuePair<string, List<string>>, in modo da ottenere la chiave, è sufficiente utilizzare la proprietà Key. Come questo:

var emailAdd = statesToEmailDictionary 
    .FirstOrDefault(x => x.Value.Contains(state)) 
    .Key; 

In alternativa, ecco l'equivalente in sintassi di query:

var emailAdd = 
    (from p in statesToEmailDictionary 
    where p.Value.Contains(state) 
    select p.Key) 
    .FirstOrDefault(); 
+0

non è 'FirstOrDefault (...). Key' pericoloso, come in un comportamento imprevisto quando si verifica "OrDefault" qui ? –

+2

@ChrisMarisic Il caso 'OrDefault' restituisce il valore predefinito del tipo su cui si sta iterando. Per i tipi di riferimento, è 'null', ma per i tipi di valore, sarà una nuova istanza di quel tipo. Poiché 'KeyValuePair ' è un tipo di valore (ad esempio una 'struct'), il caso 'OrDefault' non genererà un'eccezione di riferimento null. Dato che 'TKey' è' stringa', '.Key' di quella nuova istanza sarà' null'. –

1
var emailAdd = statesToEmailDictionary 
    .FirstOrDefault(x => x.Value != null && x.Value.Contains(state)) 
    .Key; 

Ma se siete alla ricerca di prestazioni, suggerirei invertire il dizionario e la creazione di un dizionario di <state, email> per fare ciò che stai cercando.

// To handle when it's not in the results 
string emailAdd2 = null; 
foreach (var kvp in statesToEmailDictionary) 
{ 
    if (kvp.Value != null && kvp.Value.Contains(state)) 
    { 
     emailAdd2 = kvp.Key; 
     break; 
    } 
} 
+0

un modo per gestire 'NullReferenceException'? –

+0

Io non la penso così, almeno in un liner. Modificato con un controllo non LINQ. Fa la stessa cosa del LINQ che fa: scorre in ogni valore finché non ne trova uno, quindi esce dal ciclo. Se non ne trova mai uno, viene mantenuto il valore originale di null. –

+1

In realtà, se stai ricevendo una NullReferenceException, la lista stessa deve essere stata nulla. Puoi gestirlo all'interno del lambda. Aggiornato. –

-1
var temp = statesToEmailDictionary.Where(x => x.Value.Contains(state)).FirstOrDefault(); 
var emailAdd = temp != null ? temp.Key : string.Empty; 
+1

'KeyValuePair ' è una struct, quindi 'temp' non sarà mai nullo. –

+0

Ho lo stesso caso d'uso in cui devo ottenere il valore quando key = [email protected] Sono stanco al di sotto del quale non sto dando l'output previsto. var emailAdd = statesToEmailDictionary.FirstOrDefault (x => x.Key == "[email protected]"). Valore; – Blossom

2

Penso che si desidera:

var emailAdd = statesToEmailDictionary.FirstOrDefault(x => x.Value.Any(y => y.Contains(state))).Key; 
1

Ciò che tutti in questa discussione non ha menzionato è che il metodo FirstOrDefault è disponibile solo tramite Linq:

using System; 
using System.Collections.Generic; 
// FirstOrDefault is part of the Linq API 
using System.Linq; 

namespace Foo { 
    class Program { 
     static void main (string [] args) { 
      var d = new Dictionary<string, string>() { 
       { "one", "first" }, 
       { "two", "second" }, 
       { "three", "third" } 
      }; 
      Console.WriteLine (d.FirstOrDefault (x => x.Value == "second").Key); 
     } 
    } 
} 
0

Simple Linq fare proprio questo

Dim mKP = (From mType As KeyValuePair(Of <Key type>, <Value type>) In <Dictionary> 
      Where mType.Value = <value seeked> Select mType).ToList 

If mKP.Count > 0 then 
    Dim value as <value type> = mKP.First.Value 
    Dim key as <Key type> = mKP.First.Key 
End if 

Naturalmente se ci sono valori duplicati Ciò restituirà più di un KeyValuePair

0
var emailAdd = statesToEmailDictionary.First(x=>x.Value.Contains(state)).Key;