none
how to define and initialize lookup directly? RRS feed

  • Question

  • got some compile errors with the following code

    // convert dictionary to lookup 
                Dictionary<int, Object> b = new Dictionary<int, Object>();
                Lookup<int, Object> a = b.ToLookup<int, Object>;
                // initialize lookup directly
                Lookup<int, Object> a = new Lookup<int, object>();
    


    找到我了, 你又能怎樣呢? 我又能怎樣呢?

    Thursday, August 7, 2014 11:05 AM

Answers

  • "if use a dictionary and then assign dictionary to lookup and then add a duplicate item to it"

    You can't add something to a Lookup<K,V> object, it's immutable. In general, Lookup<K,V> is not a general purposes collection like Dictionary and List. It's intended to store the result of ToLookup and not much more, that's why you can't create it.

    What you need is a so called MultiDictionary but this kind of collection doesn't yet exists in the framework (there's an experimental one in the works).

    Usually you can use something like Dictionary<int, List<object>> for such purposes.

    Friday, August 8, 2014 8:58 AM
    Moderator
  • 找到我了, 你又能怎樣呢? 我又能怎樣呢?

    You can write like this:

    Dictionary <int, object> a = new Dictionary <int, object> ();

    Lookup<int, object> b = (Lookup<int, object>)a.ToLookup(p => p.Key , p => p.Value);

    So it works.

    Friday, August 8, 2014 9:02 AM
  • Yes the lookup can have duplicates as the values with same key are grouped together. If you need duplicates then you need to use other initial container than dictionary like list.

    For example

    List<Tuple<int, dynamic>> a = new List<Tuple<int, dynamic>>(); a.Add(new Tuple<int,dynamic>(1, 1)); a.Add(new Tuple<int,dynamic>(2, 2)); a.Add(new Tuple<int,dynamic>(1, 3)); var lookup = a.ToLookup(x => x.Item1, x => x.Item2);

    List<Tuple<intdynamic>> b = new List<Tuple<intdynamic>>();
     
    foreach (var group in lookup)
    {
        int key = group.Key;
     
        foreach (var value in group)
        {
            b.Add(new Tuple<intdynamic>(key, value));
        }
    }



    • Edited by MasaSam Friday, August 8, 2014 9:07 AM
    • Marked as answer by CaillenModerator Monday, August 18, 2014 2:52 AM
    Friday, August 8, 2014 9:04 AM

All replies

  • The first usage of ToLookup extension method is invalid and in second case the error is that Lookup does not have constructor.

    The first case of using ToLookup extension method could be corrected with following changes.

    Dictionary<int, Object> b = new Dictionary<int, Object>();
    ILookup<int, Object> a = b.ToLookup(x => { return x.Key; }, x => { return x.Value; });

    Thursday, August 7, 2014 11:35 AM
  • how about Lookup<int, dynamic> a = new Lookup<int, dynamic>();?

    if without dictionary, how to use lookup directly?

    as i know lookup can have duplicate, dictionary do not have duplicate


    找到我了, 你又能怎樣呢? 我又能怎樣呢?

    Thursday, August 7, 2014 1:12 PM
  • moreover, 

    if use a dictionary and then assign dictionary to lookup

    and then add a duplicate item to it

    it sounds works

    but further thinking

    it can not change back to dictionary, since it allow duplicate

    it will have data loss in previous data if use this method


    找到我了, 你又能怎樣呢? 我又能怎樣呢?

    Friday, August 8, 2014 8:26 AM
  • "if use a dictionary and then assign dictionary to lookup and then add a duplicate item to it"

    You can't add something to a Lookup<K,V> object, it's immutable. In general, Lookup<K,V> is not a general purposes collection like Dictionary and List. It's intended to store the result of ToLookup and not much more, that's why you can't create it.

    What you need is a so called MultiDictionary but this kind of collection doesn't yet exists in the framework (there's an experimental one in the works).

    Usually you can use something like Dictionary<int, List<object>> for such purposes.

    Friday, August 8, 2014 8:58 AM
    Moderator
  • 找到我了, 你又能怎樣呢? 我又能怎樣呢?

    You can write like this:

    Dictionary <int, object> a = new Dictionary <int, object> ();

    Lookup<int, object> b = (Lookup<int, object>)a.ToLookup(p => p.Key , p => p.Value);

    So it works.

    Friday, August 8, 2014 9:02 AM
  • Yes the lookup can have duplicates as the values with same key are grouped together. If you need duplicates then you need to use other initial container than dictionary like list.

    For example

    List<Tuple<int, dynamic>> a = new List<Tuple<int, dynamic>>(); a.Add(new Tuple<int,dynamic>(1, 1)); a.Add(new Tuple<int,dynamic>(2, 2)); a.Add(new Tuple<int,dynamic>(1, 3)); var lookup = a.ToLookup(x => x.Item1, x => x.Item2);

    List<Tuple<intdynamic>> b = new List<Tuple<intdynamic>>();
     
    foreach (var group in lookup)
    {
        int key = group.Key;
     
        foreach (var value in group)
        {
            b.Add(new Tuple<intdynamic>(key, value));
        }
    }



    • Edited by MasaSam Friday, August 8, 2014 9:07 AM
    • Marked as answer by CaillenModerator Monday, August 18, 2014 2:52 AM
    Friday, August 8, 2014 9:04 AM
  • Here's my approach to achieve this behavior.

    public abstract class Lookup<TKey, TElement> : KeyedCollection<TKey, ICollection<TElement>>
    {
      protected override TKey GetKeyForItem(ICollection<TElement> item) =>
        item
        .Select(b => GetKeyForItem(b))
        .Distinct()
        .SingleOrDefault();
    
      protected abstract TKey GetKeyForItem(TElement item);
    
      public void Add(TElement item)
      {
        var key = GetKeyForItem(item);
        if (Dictionary != null && Dictionary.TryGetValue(key, out var collection))
          collection.Add(item);
        else
          Add(new List<TElement> { item });
      }
    
      public void Remove(TElement item)
      {
        var key = GetKeyForItem(item);
        if (Dictionary != null && Dictionary.TryGetValue(key, out var collection))
        {
          collection.Remove(item);
          if (collection.Count == 0)
            Remove(key);
        }
      }
    }

    Usage:

     
    public class Item
    {
      public string Key { get; }
      public string Value { get; set; }
      public Item(string key, string value = null) { Key = key; Value = value; }
    }
    
    public class Lookup : Lookup<string, Item>
    {
      protected override string GetKeyForItem(Item item) => item.Key;
    }
    
    static void Main(string[] args)
    {
      var toRem = new Item("1", "different");
      var single = new Item("2", "single");
      var lookup = new Lookup()
      {
        new Item("1", "hello"),
        new Item("1", "hello2"),
        new Item(""),
        new Item("", "helloo"),
        toRem,
        single
      };
    
      lookup.Remove(toRem);
      lookup.Remove(single);
    }
    Note: the key must be immutable (or remove and re-add upon key-change).

    Shimmy

    Tuesday, August 22, 2017 7:29 PM