Click here to Skip to main content
15,911,890 members
Please Sign up or sign in to vote.
3.00/5 (2 votes)
See more:
Hi Guys,

For whatever reason, I'd like to hold a dictionary of type object, keyed by a string.
I'd then like to have a list of strings, that when accessed by an itterator instead of returning the string ... returns the object in the dictionary that is keyed by the string..

eg.

Dictionary 'dct' contains ... { { "i1","Mark" },{ "i2", "Fred" }, { "i3", "Harry" } }
List 'lst' contains { "i2", "i1", "i3" }

then ...

foreach( object a in lst ) {
Console.WriteLine( a )
}

would produce the result ...

Fred
Mark
Harry

How do I achieve this?

Many thanks in advance for your help

8^)
Mark
Posted
Comments
Sergey Alexandrovich Kryukov 15-Mar-13 17:03pm    
Did you try anything so far? The problems looks like more then trivial.
—SA
MarkAGr 15-Mar-13 17:15pm    
I did it in VB6.0 a few years ago ...
And it was deceptively difficult.

I'm trying to produce a reference system that can be made persistent AND will port over more than one language ( and not necessarily any of the CLR/Microsoft languages either.) This example is just for c#.
Sergey Alexandrovich Kryukov 15-Mar-13 18:14pm    
Why remembering the lame of VB6. It's good not to remember nightmares... In .NET, it's non-deceptively easy... :-)
—SA
MarkAGr 15-Mar-13 18:25pm    
:D ... point accepted.
Sergey Alexandrovich Kryukov 15-Mar-13 18:34pm    
Great. :-)

You can have any reason to store things in a dictionary.
But the rest is quite confusing to me: why exactly that way?

You have several options, like these (LinqPad[^] script, but you can see the concept)

C#
Dictionary<string, string> dictionary = new Dictionary<string,string>() {{"i1","John"},{"i2","Paul"},{"i3","Gloria"}};
List<string> list = new List<string>() {"i1","i3"};

// Option A
foreach(string index in list)
{
    dictionary[index].Dump();
}

// Option B
(from index in list select dictionary[index]).Dump();

// Option C
(from index in list join element in dictionary on index equals element.Key select element.Value).Dump();

// Option D
foreach(var @object in dictionary.Where(element => list.Contains(element.Key)).Select(element => element.Value))
{
	@object.Dump();
}


But you can find some other options here too: http://stackoverflow.com/questions/200574/linq-equivalent-of-foreach-for-ienumerablet[^]

And here is a neater solution based on option D, by extracting the query in an extension method:

C#
public static class DictionaryExtension
{
    public static IEnumerable<T> Filter<T> (this Dictionary<string, T> dictionary, List<string> list)
    {
        return dictionary.Where(element => list.Contains(element.Key)).Select(element => element.Value);
    }
}
....
foreach(var @object in dictionary.Filter&lt;string&gt;(list))
    {
        @object.Dump();
    }
 
Share this answer
 
v3
Comments
MarkAGr 15-Mar-13 17:33pm    
This is in the right direction ....

Option A is the closest to my want ... however I was hoping to have that done for me automatically by the iterator. It'd save me a whole load of work.

The dictionary would have a string as the key and a generic "object" as the data.
The super class would also hold the key.
The lists are merely lists of keys to the data.

Thanks.
Zoltán Zörgő 16-Mar-13 2:51am    
See update with option D, and the final suggestion.
Your example of
C#
foreach (object a in lst){
  Console.WriteLine( a )
}

never actually references the Dictionary of interest.
I think an (extension) method that returns IEnumerable<T> would encapsulate what you seem to want:
C#
using System.Linq;
public static class ExtensionMethod
{
  public static IEnumerable<Tvalue> SubSet<Tkey, Tvalue>(this Dictionary<Tkey, Tvalue> dict, IEnumerable<Tkey> inner, Tvalue notFoundValue = default(Tvalue))
  {
    if (inner == null)
      throw new ArgumentNullException("inner");
    return inner.Select(item => {
      Tvalue val;
      if (!dict.TryGetValue(item, out val))
      {
        val = notFoundValue;
      }
      return val;
    });
  }
}

Notice that I've provided a way to specify the value to be returned if the key from the list is not found in the Dictionary.
So you would use this like:
C#
const string NotFound = "NotFound";            // could be string.Empty, etc.
foreach (var a in dict.SubSet(lst, NotFound)){ // the notFoundValue is optional
  Console.WriteLine( a )
}
 
Share this answer
 
Comments
MarkAGr 15-Mar-13 19:00pm    
Am I right in thinking this isn't base c# but LINQ ?
Does this compile under a none microsoft c# compiler?
... like mcs or gmcs?
Matt T Heffron 15-Mar-13 19:12pm    
Yes, this is LINQ.
What are the restrictions of these other compilers?
(Probably don't handle default arguments, either...)
(You didn't specify any constraints in posing the question.)
MarkAGr 15-Mar-13 22:22pm    
Well, I did ask for a C# solution, not a Microsoft framework solution.
Based on your comments above, I'll redo this without LINQ:
C#
public static class ExtensionMethods
{
  public static IEnumerable<Tvalue> SubSet<Tkey, Tvalue>(this Dictionary<Tkey, Tvalue> dict, IEnumerable<Tkey> inner, Tvalue notFoundValue = default(Tvalue))
  {
    if (dict == null)
      throw new ArgumentNullException("dict");
    if (inner == null)
      throw new ArgumentNullException("inner");
    foreach (Tkey item in inner)
    {
      Tvalue val;
      if (!dict.TryGetValue(item, out val))
      {
        val = notFoundValue;
      }
      yield return val;
    });
  }

  public static IEnumerable<Tvalue> SubSet<Tkey, Tvalue>(this Dictionary<Tkey, Tvalue> dict, IEnumerable<Tkey> inner)
  {
    return SubSet(dict, inner, default(Tvalue));
  }
}


This (and the previous Solution) are untested but it ought to work! ;). (Not even compiled. Caveat emptor!)
 
Share this answer
 
v2
Comments
MarkAGr 15-Mar-13 22:24pm    
Wow! Now I'm going to spend a while looking at this ...because I need to know how this is working ( if it does ;) )

Thanks for all this effort.
You don't really need the list; it looks totally redundant. The only possible reason to iterate by the keys is when you need to preserve the order of items, and the right order is represented by the order in the list, which is not the same as the order in the dictionary, [EDIT] of the list contains only a subset of the keys, as you correctly noted in your comment. It's very good that you know the purpose [END EDIT].

Nevertheless, you can do it. As I can see, your only problem is getting a value by a key. In your loop, your key is a and, as getting the dictionary value from the dictionary is the main feature of the dictionary, please look at MSDN help page and see how to do it. You can use the indexed property, using, in C#, '[]' syntax. And read about indexed properties in C# reference. This should be more than enough.

However, as I say, you are rather advised to ignore your list (see my first paragraphs) and iterate using foreach(var pair in yourDictionary) { /* ... */ }, where pair will be:
http://msdn.microsoft.com/en-us/library/5tbh8a42.aspx[^].

This is really all what you need, event more than that.

I hope you understand why I'm not showing any code. If you don't do such trivial things with your own hands, most likely, after looking at the code, your skills will remain on the same level, called "next to nothing", which I think is not what you want.

Thank you for understanding, good luck,
—SA
 
Share this answer
 
v2
Comments
MarkAGr 15-Mar-13 17:28pm    
You've missed the point ...
There maybe a several lists ... there may many dictionaries.
The dictionary might be large ... the individual lists might be small subsets.

I do know what I'm asking and I do know what I'm asking it for.

I find your answer condescending, but I'll try not to be offended.

Thanks for the effort.
Sergey Alexandrovich Kryukov 15-Mar-13 18:01pm    
I don't see why do you think that I'm missing any point. I described how to do the search by the list of keys and explained the case when you might need it; the only difference is order, many or just one list or dictionary — does not matter. Yes, a sub-set is also a valid point, but again, I answered how to do it, that's all what you need.

Thank you very much for understanding.
—SA

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900