0

I have a dictionary named as dict_id_names:

Dictionary<int,List<string>> dict_id_names = new Dictionary<int,List<string>();

Suppose dictionary contains 3 key-value pairs:

  • id = 1: List contains names "Robin", "Rahul", "Adam", "Akhtar",

  • id = 2: List contains names "Sun", "Mon", "Adam",

  • id = 3: List contains names "a", "b", "c"

Now my question is that if I only have name "Adam" then how can I get the respective key / keys as 1 and 2 in the above case from the dictionary?

Yeldar Kurmangaliyev
  • 33,467
  • 12
  • 59
  • 101
  • 1
    Is it required that the reverse lookup would be ~O(1) like normal dictionary? Note that all the answers below involve a full scan of the dictionary. – shay__ Nov 05 '15 at 09:16

5 Answers5

4

You can use LINQ:

var keyValsWithAdamValue = dict_id_names.Where(kv => kv.Value.Contains("Adam"));

foreach(var kv in keyValsWithAdamValue)
    Console.WriteLine("{0}|{1}", kv.Key, String.Join(",", kv.Value));

If you just want the IDs you can select them and use ToList/ToArray to create a collection:

List<int> idsWithAdamInList = dict_id_names
    .Where(kv => kv.Value.Contains("Adam"))
    .Select(kv => kv.Key)
    .ToList();

Note that this approach is like a loop over the dictionary. You don't benefit from the fast lookup performance of a dictionary if you're enumerating it. It's not designed for this purpose. But it's simple and readable code and perfect if performance is not so important in this case.

Tim Schmelter
  • 450,073
  • 74
  • 686
  • 939
2

You can use the following LINQ query:

int[] ids = dict_id_names
                    .Where(pair => pair.Value.Contains("Adam"))
                    .Select(pair => pair.Key)
                    .ToArray();

Console.WriteLine(String.Join(',', ids)); // 1,2

It will result in an array [1, 2], because both of these dictionary entries contain Adam in its string list.

Yeldar Kurmangaliyev
  • 33,467
  • 12
  • 59
  • 101
1
string name = "Adam";
foreach(int key in dict_id_names.Keys)
{
    List<string> valueList = dict_id_names[key];

    if(valueList.Contains(name);
       Console.WriteLine(id);
}

This should help.

mybirthname
  • 17,949
  • 3
  • 31
  • 55
  • Yes i tried this before but is there any other way or method by which there is no necessity of full scan of the dictionary? –  Nov 05 '15 at 09:35
0

Something like -

var dict_id_names= new Dictionary<int,List<string>>();
dict_id_names.Add(1, new List<string> { "Robin", "Rahul", "Adam", "Akhtar" });
var id = dict_id_names.Where(a => a.Value.Contains("Adam")).FirstOrDefault().Key;
Amit Kumar Ghosh
  • 3,618
  • 1
  • 20
  • 24
0

I'd just like to offer a different perspective, for comparative purposes.

Suppose that you are doing this reverse lookup frequently, and you want it to be better than an O(N) operation.

You can achieve that using two dictionaries instead of one. To simplify things in this example, I'll use Microsoft's pre-release MultiValueDictionary (which you can obtain via NuGet).

This approach yields an O(1) lookup:

using System;
using System.Collections.Generic;
using System.Linq;

namespace Demo
{
    internal class Program
    {
        public static void Main()
        {
            var names = new Names();

            names.Add(1, "Robin");
            names.Add(1, "Rahul");
            names.Add(1, "Adam");
            names.Add(1, "Akhtar");

            names.Add(2, "Sun");
            names.Add(2, "Mon");
            names.Add(2, "Adam");

            names.Add(3, "a");
            names.Add(3, "a");
            names.Add(3, "c");

            Console.WriteLine("IDs for Adam:");

            foreach (int id in names.IdsOf("Adam"))
                Console.WriteLine(id);
        }

        public sealed class Names
        {
            readonly MultiValueDictionary<int, string> names = new MultiValueDictionary<int, string>();
            readonly MultiValueDictionary<string, int> lookup = new MultiValueDictionary<string, int>();

            public void Add(int id, string name)
            {
                names.Add(id, name);
                lookup.Add(name, id);
            }

            public IEnumerable<int> IdsOf(string name)
            {
                IReadOnlyCollection<int> result;

                if (lookup.TryGetValue(name, out result))
                    return result;
                else
                    return Enumerable.Empty<int>();
            }

            public IEnumerable<string> NamesOf(int id)
            {
                IReadOnlyCollection<string> result;

                if (names.TryGetValue(id, out result))
                    return result;
                else
                    return Enumerable.Empty<string>();
            }
        }
    }
}
Matthew Watson
  • 104,400
  • 10
  • 158
  • 276