1

Looking at the docs for KeyedCollection i read the following::

The KeyedCollection class provides both O(1) indexed retrieval and keyed retrieval that approaches O(1).

https://docs.microsoft.com/en-us/dotnet/api/system.collections.objectmodel.keyedcollection-2?view=netcore-3.1

I do not fully understand what this means. I personally would think that indexed retrieval and keyed retrieval are the same since a dictionary indexes by keys. I feel a bit vague about the terms 'indexed retrieval' and 'keyed retrieval' altogether i suppose.

So what's the difference, and why is the complexion different?

Additional info: I personally would like to use the keyedCollection because I have a list that will be added to a lot. Now and then i need to fetch an item by an id - a Guid and return some data. I also periodically will go through the list and delete any items i no longer use.

Sample;

    /// <summary>
    /// A collection of leases. Implements <see cref="KeyedCollection{TKey,TItem}"/> which is a dictionary-list hybrid.
    /// </summary>
    public class LeaseInfoCollection : KeyedCollection<Guid, LeaseInfo>
    {
        #region Construction and Destruction

        /// <inheritdoc />
        public LeaseInfoCollection()
        {
        }

        /// <inheritdoc />
        public LeaseInfoCollection(IEqualityComparer<Guid> comparer)
            : base(comparer)
        {
        }

        /// <inheritdoc />
        public LeaseInfoCollection(IEqualityComparer<Guid> comparer, int dictionaryCreationThreshold)
            : base(comparer, dictionaryCreationThreshold)
        {
        }

        #endregion

        #region Overrides of KeyedCollection<string,LeaseInfo>

        /// <inheritdoc />
        protected override Guid GetKeyForItem(LeaseInfo item)
        {
            return item.LeaseId;
        }

        #endregion
    }
sommmen
  • 2,980
  • 1
  • 12
  • 23
  • 1
    Hint: To use a custom object as a dictionary key based on its properties, you have to implement `GetHashCode()` and `Equals()` on the custom object. Possible values for a hash code are between `int.MinValue` and `int.MaxValue`, so clearly collisions are possible. – Llama May 07 '20 at 09:10
  • 3
    It's just indexed retrieval is "by index" ( `myCollection[i]` ) and keyed is "by key" ( `myCollection[myKey]` ). Index refers to a specific _position_ in the collection, while the position of an element with a specific key could be anywhere in the collection, depending on how the datastructure handles keying. So you need to map key to position first, which has a (hopefully) small impact on time complexity. – Fildor May 07 '20 at 09:17
  • 1
    @Fildor that makes sense - great – sommmen May 07 '20 at 09:58
  • @John so if i get you right, i currently have MyCustomObject.Id as 'key' indexer for the keyedcollection. I should then also override gethashcode to use the guid so the dict indexes based on that - or am i wrong here? I'm now thinking that i do not need keyedcollection at all, i can just override gethashcode to use the guid and then use a dictionary instead - any advice? – sommmen May 07 '20 at 09:59
  • Disregard that last comment - i was being dumb. – sommmen May 07 '20 at 10:07

1 Answers1

0

The answer to this question is in the next paragraph of the documentation:

The KeyedCollection<TKey,TItem> class is a hybrid between a collection based on the IList<T> generic interface and a collection based on the IDictionary<TKey,TValue> generic interface. Like collections based on the IList<T> generic interface, KeyedCollection<TKey,TItem> is an indexed list of items. Like collections based on the IDictionary<TKey,TValue> generic interface, KeyedCollection<TKey,TItem> has a key associated with each element.

From this paragraph we can learn that we can access elements of the KeyedCollection collection using their ordinal indexes or their keys.

Here is sample (based on the sample from MSDN) to show these two approaches to retrieve elements of KeyedCollection:

public class OrderItem
{
    public OrderItem(string partNumber) => PartNumber = partNumber;

    public string PartNumber { get; }
}

// Custom KeyedCollection.
public class SimpleOrder : KeyedCollection<string, OrderItem>
{
    // Here we define how to get Key from Item for our custom KeyedCollection.
    protected override string GetKeyForItem(OrderItem item) => item.PartNumber;
}

internal static class Program
{
    private static void Main()
    {
        KeyedCollection<string, OrderItem> kc = new SimpleOrder();

        kc.Add(new OrderItem("#0"));
        kc.Add(new OrderItem("#1"));

        // Retrieve item by index.
        Console.WriteLine(kc[0].PartNumber);

        // Retrieve item by key.
        Console.WriteLine(kc["#1"].PartNumber);
    }
}
Iliar Turdushev
  • 3,910
  • 1
  • 4
  • 19
  • I still was not clear about the text after, but when you string it together like this it makes sense - much obliged. – sommmen May 07 '20 at 10:00