11

I am having trouble getting the key by specifying a value. What is the best way I can achieve this?

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("test1@gmail.com", st1);
statesToEmailDictionary.Add("test2@gmail.com", st2);
statesToEmailDictionary.Add("test3@gmail.com", st3);

var emailAdd = statesToEmailDictionary.FirstOrDefault(x => x.Value.Where(y => y.Contains(state))).Key;
Sam
  • 7,252
  • 16
  • 46
  • 65
Krishh
  • 4,111
  • 5
  • 42
  • 52

7 Answers7

19

The return value from FirstOrDefault will be a KeyValuePair<string, List<string>>, so to get the key, simply use the Key property. Like this:

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

Alternatively, here's the equivalent in query syntax:

var emailAdd = 
    (from p in statesToEmailDictionary
     where p.Value.Contains(state)
     select p.Key)
    .FirstOrDefault();
p.s.w.g
  • 146,324
  • 30
  • 291
  • 331
  • Isn't `FirstOrDefault(...).Key` dangerous, as in unexpected behavior when "OrDefault" occurs here? – Chris Marisic Jul 24 '15 at 16:22
  • 2
    @ChrisMarisic The 'OrDefault' case returns the default value of the type you're iterating over. For reference types, that's `null`, but for value types, it will be a new instance of that type. Since `KeyValuePair` is a value type (i.e. a `struct`), the 'OrDefault' case will not result in a null-reference exception. Since `TKey` here is `string`, the `.Key` of that new instance will be `null`. – p.s.w.g Jul 24 '15 at 19:23
2

I think you want:

var emailAdd = statesToEmailDictionary.FirstOrDefault(x => x.Value.Any(y => y.Contains(state))).Key;
Adam
  • 741
  • 6
  • 4
2

What everyone in this thread failed to mention is that the FirstOrDefault method is only available through 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);
        }
    }
}
erapert
  • 1,383
  • 11
  • 15
1
var emailAdd = statesToEmailDictionary
    .FirstOrDefault(x => x.Value != null && x.Value.Contains(state))
    .Key;

But if you're looking for performance, I'd suggest reversing your dictionary and creating a dictionary of <state, email> to do what you're looking for.

// 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;
    }
}
Joe Enos
  • 39,478
  • 11
  • 80
  • 136
  • any way to handle `NullReferenceException`? – Ilya Ivanov May 31 '13 at 15:23
  • I don't think so, in a one-liner at least. Edited with a non-LINQ check. It does the same thing as the LINQ one does - loops through each value until it finds one, then breaks out of the loop. If it never finds one, the original value of null is kept. – Joe Enos May 31 '13 at 15:29
  • 1
    Actually, if you were getting a NullReferenceException, then the list itself must have been null. You can handle that inside the lambda. Updated. – Joe Enos May 31 '13 at 15:32
1
var emailAdd = statesToEmailDictionary.First(x=>x.Value.Contains(state)).Key;
Andrey Korneyev
  • 26,353
  • 15
  • 70
  • 71
G.J
  • 31
  • 1
  • 4
0

Simple Linq to do just that

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 

Of course if there are duplicate values this will return more than one KeyValuePair

p.s.w.g
  • 146,324
  • 30
  • 291
  • 331
-1
var temp = statesToEmailDictionary.Where( x => x.Value.Contains(state)).FirstOrDefault();
var emailAdd = temp != null ? temp.Key : string.Empty;
SamiHuutoniemi
  • 1,576
  • 2
  • 16
  • 35
  • 1
    `KeyValuePair` is a struct, so `temp` will never be null. – p.s.w.g May 31 '13 at 15:26
  • I have the same use case where I have to get the value when key = test1@gmail.com.I tired below which is not giving expected output. var emailAdd = statesToEmailDictionary.FirstOrDefault(x => x.Key == "test1@gmail.com").Value; – Blossom Nov 02 '17 at 19:26