I need a collection that exposes [] operator, contains only unique objects, and are generic. Anyone can help?
Dictionary(Of TKey, TValue) Class represents a collection of keys and values.
HashSet<T>
It depends what you mean by "exposes the [] operator."
If you want to be able to access objects in a unique collection by some arbitrary key, then use a Dictionary<string key, object value>.
If you want to be able to create a list of unique objects which permits access by an ordinal index, in the order in which objects were added, you will need to roll something of your own. I am not aware of any framework class that offers both uniqueness like a HashSet<T> and also allows access to objects in the order in which they were added, like a List<T>. SortedSet<T> almost does it, but does not have indexer access - so while it does maintain order, it does not allow access using that order except through enumeration. You could use Linq extension method ElementAt to access the element at a particular ordinal index, but performance would be very bad since this method works by iteration.
You could use also Dictionary<int key, object value> but you will still have to maintain the index yourself, and if anything is ever removed, you'd have a hole in your list. This would be a good solution if you never had to remove elements.
To have both uniqueness and access by index, and also be able to remove elements, you need a combination of a hash table and an ordered list. I created such a class recently. I don't think this is necessarily the most efficient implementation since it does its work by keeping two copies of the lists (one as a List<T> and one as a HashSet<T>).
In my situation, I valued speed over storage efficiency, since the amount of data wasn't large. This class offers the speed of a List<T> for indexed access and the speed of a HashTable<T> for element access (e.g. ensuring uniqueness when adding) at the expense of twice the storage requirements.
An alternative would be to use just a List<T> as your basis, and verify uniqueness before any add/insert operation. This would be more memory efficient, but much slower for add/insert operations because it doesn't take advantage of a hash table.
Here's the class I used.
http://snipt.org/xlRl
The HashSet class should do the trick. See HashSet(Of T) for more information. If you need them to maintain a sorted order, the SortedSet should do the trick. See SortedSet(Of T) for more information about that class.
If you're looking to store unique objects (entities, for example) while exposing a [], then you want to use the KeyedCollection class.
MSDN KeyedCollection
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
// This class represents a very simple keyed list of OrderItems,
// inheriting most of its behavior from the KeyedCollection and
// Collection classes. The immediate base class is the constructed
// type KeyedCollection<int, OrderItem>. When you inherit
// from KeyedCollection, the second generic type argument is the
// type that you want to store in the collection -- in this case
// OrderItem. The first type argument is the type that you want
// to use as a key. Its values must be calculated from OrderItem;
// in this case it is the int field PartNumber, so SimpleOrder
// inherits KeyedCollection<int, OrderItem>.
//
public class SimpleOrder : KeyedCollection<int, OrderItem>
{
// The parameterless constructor of the base class creates a
// KeyedCollection with an internal dictionary. For this code
// example, no other constructors are exposed.
//
public SimpleOrder() : base() {}
// This is the only method that absolutely must be overridden,
// because without it the KeyedCollection cannot extract the
// keys from the items. The input parameter type is the
// second generic type argument, in this case OrderItem, and
// the return value type is the first generic type argument,
// in this case int.
//
protected override int GetKeyForItem(OrderItem item)
{
// In this example, the key is the part number.
return item.PartNumber;
}
}
Related
I have an array of generic type inside my class.
I am practicing implementing open addressing HashTable (generic version) with different probing - and I want to mark slots of deleted elements, so I can tweak optimisation later (swap items during search and insert into "deleted" slots).
Usually people use some kind of dummy object for this purposes - they assign it to the slot of deleted item and than compare array elements to it during other operations.
But I am not sure if I can do it with generic type in C# - I want to use the HashTable with any Key types - both reference and value. So I don't want to Key to implement any kind of interface.
I saw it used in Java like this:
K DUMMY_DELETED = (K) (new Object());
if(keys[i] == DUMMY_DELETED)
{
...
}
Is there a way to work this out for C# without obliging Key to implement some interface? Or should I use a wrapper for the key-value inside my class?
Generics are implemented differently in Java and C#, so you can't use objects other than the generic type like you can in Java. Some options:
Use Dictionary<TKey, object> and do the cast yourself for non-deleted items
Constrain TValue to an interface that has an IsDeleted property
Define a wrapper class that contains the object, has a pass-through Value property, and has an IsDeleted property. (Similar to Nullable<T>)
Inherit from Dictionary<TKey, KValue> and keep track of deleted "slots" in a separate property.
For IDictionary<TKey, TValue> the Keys and Values properties are of type ICollection<TKey> and ICollection<TValue>.
For IReadonlyDictionary<TKey, TValue> the Keys and Values properties are of type IEnumerable<TKey> and IEnumerable<Value>.
Why aren't the properties of IReadonlyDictionary<TKey, TValue> just the corresponding ReadOnly interfaces, namely IReadOnlyCollection<TKey> and IReadOnlyCollection<TValue>?
One might wonder why both properties aren't of type IEnumerable as you can't alter the dictionary through the two properties but through Add and Remove methods. In fact the ICollection returned by IDictionary.Keys has the IsReadOnly property set, so tried to invoke Add or Remove on the property throws an NotSupportedException with the additional information Mutating a key collection derived from a dictionary is not allowed.
If one anyways can't alter the dictionary through its properties, why aren't the both IReadOnlyCollections?
The IReadOnly interfaces was first introduced in .NET 4.5, so I guess that can't be done without an undesired breakage of backward compatibility.
It puts less of a burden on people implementing a custom IReadonlyDictionary<TKey, TValue> if they did not want to use things that derived from IReadOnlyCollection for their backing stores.
If you are using the built in implementation of ReadOnlyDictionary there is nothing stopping you from casting the interface.
IReadOnlyDictionary<Foo, Bar> baz = GetDictionary();
IEnumerable<Foo> keys = baz.Keys;
IReadOnlyCollection<Foo> keysCollection = keys as IReadOnlyCollection<Foo>;
if(keysCollection != null)
{
//This code will execute for the built in implmentation of `ReadOnlyDictionary<Foo, Bar>`
}
You don't modify either the collection of keys or the collection of values through the Keys and Values properties. You only use those properties to access the keys and values. So it doesn't matter whether or not they are explicitly read-only collections.
The keys and values can only be modified by adding items to the dictionary, which you can't do with an IReadOnlyDictionary.
Also, using an ICollection places an additional restriction on how a particular implementation of IReadOnlyDictionary returns those properties. An IEnumerable<T> can be implemented in many more ways, even by a method using a yield statement. If the returned type is ICollection<T> then the dictionary would be forced to populate something that implements ICollection<T>. It might still do that, but if something implements ICollection<T> then it also implements IEnumerable<T>.
So I'd wonder the other way - why does an IDictionary<T> return ICollection<T> for those properties instead of IEnumerable<T>. (There might be a good reason. But now I'm wondering.)
IEnumerable<T> allows you to take advantage of Linq methods and the whole iterator infrastructure directly, without having to perform a cast.
You can't modify the data in the underlying ReadOnlyDictionary implementation anyway, even through the Key and Value collections. IEnumerable<T> doesn't care whether its underlying implementation is read-only or not.
Out of curiosity: What comparer is used when sorting a bunch of objects using the following extension method?
OrderBy(x=> x)
Background: I have to check wether two ISet< T > instances contain the same elements and considered to use the
bool setsEqual = MySet.SequenceEqual(OtherSet);
method. As the order of those elements contained in the sets are not defined and may differ, a SequenceEqual would fail in those cases where the internal order is not the same. So i would have to explictly define an order. As the order algo for itself is completely irrelevant as long as it´s stable, i just used an "Identity" lambda expression:
bool setsEqual = MySet.OrderBy(x => x).SequenceEqual(OtherSet.OrderBy(x => x);
But what does "Compare the objects themselves" mean to the code? As this OrderBy extension method is a generic one, there must be a default compare algo in place that is able to sort objects without knowing anything more about it, and that would mean a comparison for sorting had to be delegated to the type of the set elements itself. Is there an interface that the elements´ type would have to support, or is there a default comparer (may be comparing internal memory addresses of objects) in place?
To answer the question of sorting: sorting uses IComparable<T> or IComperable if that isn't implemented. The IComperable interfaces force you to implement a int CompareTo(object) method (or int CompareTo(T) method if you used the typed version).
The order of your elements is determined by the sign of the int. The value returned is interpreted as follows:
0: the two objects are equivalent (i.e. the same)
-1: the compared object precedes this object (i.e. comes before this object)
1: the compared object follows this object (i.e. comes after this object)
The actual value is ignored, the sign is all that matters. If you implement your own IComparable interface, you have to choose the semantics for sort order.
Many objects already implement IComparable already, like all your numbers, strings, etc. You'll need to implement it explicitly if you need to sort objects you've created yourself. It's not a bad practice if you intend those objects to be displayed in a list on screen at all.
As to your specific case, where you just need to determine if a set and another IEnumerable are equivalent, then you would use the ISet<T>.SetEquals(IEnumerable<T>) method which is implemented in the standard library set implementations. Sets, by definition, only guarantee the values are unique, so as long as the number of elements are the same, you only need to detect that all the elements in one IEnumerable can be found in the set.
The method used the IComparable<T>-or the IComparable-interface depending on which of both are implemented. If none is implemented the order is arbitrary.
However you won´t need to order you instances before comparing the sets. Simply loop one set and check if all of its elements are contained in the other set. Or use this:
var areEqual = firstSet.All(x => secondSet.Contains(x)) && secondSet.All(x => firstSet.Contains(x));
Or even simpler:
var areEqual = !firstSet.Except(secondSet).Any() && !secondSet.Except(firstSet).Any();
Both ways perform much faster than your appraoch as the iteration of elements stops when the first element is found that does not fit. Using OrderBy you´d loop all elements, regardless if there was already a mismatch.
Unlike for equality, there's no 'default' comparer for objects in general.
It seems that Comparer<TKey>.Default always returns a comparer, for any type TKey. If no sensible comparison method can be determined, you get an exception, but only once the comparer is used.
At least one object must implement IComparable.
I need to know if there is any way of ordering an IDictionary without knowing what type it is exactly ...
For example, I have a method that received an object and within this I have a Dictionary object ... all I know is that it is a Dictionary
so I can do this:
public void MyMethod(PropertyInfo propriedadeParametro, object parameters){
IDictionary dictionary = ((IDictionary) propriedadeParametro.GetValue (parameters, null));
}
but need sort the items of this Dictionary by EnumPersonalizado regardless of what the other Type "something?" has
You can't sort a dictionary. A dictionary, by definition, doesn't have an "order" of the items within it. The items are stored in some mechanism that is beyond your control that is designed to make it as efficient as possible for adding, removing, and searching.
The best that you can do is take all of the items out of the dictionary, put them in some other sort of collection, and then sort that.
As to your particular case, it's not clear to us what the type of the key or the value in the dictionary is, and that would need to be known in order to be able to try to sort the data.
see this question.
Dictionaries by themselves don't have an index order. Consider inheriting from the KeyedCollection class instead. It's a merge of a dictionary and an ordinary list, and it's designed to use a member of your items as the key, and have an index order.
There are plenty of legitimate reasons to want to apply a partial ordering to dictionaries based on key, it isn't a fundamental quality that keys be unordered, only that a given key will yield a given value.
That being said, if you find yourself with a non-generic IDictionary, it can actually be quite troublesome to 'sort' by key without knowledge of the key type. In my specific scenario, I wanted a function which would transform an IDictionary into another IDictionary where the entries could be enumerated by the ordered keys.
IDictionary ToSortedDictionary(IDictionary dictionary) {
return new SortedList(dictionary);
}
This will construct a new dictionary instance, such that traversals (foreach) will visit the entries based on the sort order of the keys.
The oddly named SortedList can be found in System.Collections and orders keys using the ÌComparable interface.
IDictionary is IEnumerable, so you can try to do something like new ArrayList(dictionary).Sort(), but it will try to cast members to IComparable, or you can use a Sort overload which accepts an IComparer object.
Another way is to use a reflection - first you find actual Keys/Values types and then you create a call to generic OrderBy.
Is there any way to retrieve a key from a SortedDictionary that is equal to a given object? To illustrate, lets say I create a dictionary that has a fairly memory-heavy, immutable key type:
var dictionary = SortedDictionary<MyHugeType, int>();
var myEnormousKey = new MyHugeType();
dictionary[myEnormousKey] = 123;
Then later on, I do something like this:
// This is a new instance, but it's identical to the previous key
var myIdenticalKey = new MyHugeType();
if(dictionary.ContainsKey(myIdenticalKey)) {
myIdenticalKey = dictionary.GetKeyEqualTo(myIdenticalKey);
}
// Use myIdenticalKey reference...
Obviously, SortedDictionary does not have a "GetKeyEqualTo" method. But is there some way I could achieve a similar effect? This would basically have the effect of intern-ing the heavy key objects so that identical instances could be discarded. I know I can do this using the SortedList class by retrieving the key's index and subsequently its matching object instance, but SortedDictionary's consistent insertion performance would be better for my uses.
Short of iterating through all the dictionary's keys to search for a match, or writing my own BST class, is there any way to achieve this end with .NET's built in collections?
You could change your value object from int to a struct or class containing both the value and the original key. Then to access the original key you can do:
dictionary[myIdenticalKey].OriginalKey
and for the value something like:
dictionary[myIdenticalKey].Value
If you override Equals() and GetHashCode() in MyHugeType with code that determines if two instances are the same, then you won't get duplicate keys in the dictionary. Is this what you mean?
You could implement the IEquatable interface in your key class. There you specify when two objects of the class are equal to each other. After that you simply test the existence of an entry using ContainsKey and when that returns true you can obtain it using the [] operator.
You could also provide a IComparer implementation to achieve the same result.