如何在C#4.0中修改ILookup对象?

时间:2010-01-02 07:19:35

标签: collections c#-4.0

在.NET 3.5发布之前,我使用

Dictionary<TKey, List<TValue>> 

用于包含数据。但我刚刚发现.NET 3.5提供了新的集合类型,它是ILookup类,可以代表我原来的复杂数据类型。

我总是使用LINQ扩展方法(ToLookup方法)创建ILookup对象。但我不知道如何修改ILookup对象。

有可能吗?或者我需要使用union方法创建并再次调用ToLookup方法。

谢谢,

3 个答案:

答案 0 :(得分:4)

你没有,这是不可改变的。您列出了两个合理的选择;要么使用子集的字典,要么继续创建新的查找。

答案 1 :(得分:4)

以下是可以操作的ILookup实现的示例。它包裹着DictionaryList个元素。它完全是通用的。我想不出更好的名字。 :)

public class LookupDictionary<TKey, TElement> : ILookup<TKey, TElement>
{
    private Dictionary<TKey, List<TElement>> _dicLookup = new Dictionary<TKey, List<TElement>>();

    public LookupDictionary()
    {

    }

    public LookupDictionary(ILookup<TKey, TElement> a_lookup)
    {
        foreach (var grouping in a_lookup)
        {
            foreach (var element in grouping)
                AddElement(grouping.Key, element);
        }
    }

    public IEnumerable<TElement> AllElements
    {
        get
        {
            return (from key in _dicLookup.Keys
                    select _dicLookup[key])
                    .SelectMany(list => list);
        }
    }

    public int Count
    {
        get 
        {
            return AllElements.Count();
        }
    }

    public IEnumerable<TElement> this[TKey a_key]
    {
        get 
        {
            List<TElement> list;
            if (_dicLookup.TryGetValue(a_key, out list))
                return list;

            return new TElement[0];
        }
    }

    public bool Contains(TKey a_key)
    {
        return _dicLookup.ContainsKey(a_key);
    }

    public void Add(TKey a_key, TElement a_element)
    {
        AddElement(a_key, a_element);
    }

    public void RemoveKey(TKey a_key)
    {
        _dicLookup.Remove(a_key);
    }

    public IEnumerator<IGrouping<TKey, TElement>> GetEnumerator()
    {
        return GetGroupings().GetEnumerator();
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return (GetGroupings() as System.Collections.IEnumerable).GetEnumerator();
    }

    private void AddElement(TKey a_key, TElement a_element)
    {
        List<TElement> list;

        if (!_dicLookup.TryGetValue(a_key, out list))
        {
            list = new List<TElement>();
            _dicLookup.Add(a_key, list);
        }

        list.Add(a_element);
    }

    private IEnumerable<IGrouping<TKey, TElement>> GetGroupings()
    {
        return from key in _dicLookup.Keys
               select new LookupDictionaryGrouping<TKey, TElement>
               {
                   Key = key,
                   Elements = _dicLookup[key]
               } as IGrouping<TKey, TElement>;
    }
}

public class LookupDictionaryGrouping<TKey, TElement> : IGrouping<TKey, TElement>
{
    public TKey Key
    {
        get;
        set;
    }

    public IEnumerable<TElement> Elements
    {
        get;
        set;
    }

    public IEnumerator<TElement> GetEnumerator()
    {
        return Elements.GetEnumerator();
    }


    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return (Elements as System.Collections.IEnumerable).GetEnumerator();
    }
}

答案 2 :(得分:0)

正如mquander所提到的,查找是不可变的。但是,您可以使用其他值或已删除的值构建新查找。

// Add a new value
myLookup = myLookup
    .SelectMany(l => l.Select(v => new {l.Key, Value = v}))
    .Union(new[] {new {Key = myNewKey, Value = myNewValue}})
    .ToLookup(a => a.Key, a => a.Value);

// Remove an old value
myLookup = myLookup
    .SelectMany(l => l.Select(v => new {l.Key, Value = v}))
    .Where(a => a.Value != myOldValue)
    .ToLookup(a => a.Key, a => a.Value);