I'm looking for a collection.
I need to be able to add elements as if using a 2D integer key, for example .Add(3, 4, element). If I add outside the range of the collection I need the collection to expand, this include negatively, although it can have a limit, for example the range of an Int16 would be good. Every element in the collection can have the same type as each other but I need to specify what that is, for example Set<type> s;
I also need to avoid slow operations such as searching when looking up an element, performance is less important when adding to the collection.
Does anyone have any ideas about what approach to use or best could provide the class in there answer.
If you want a compound key, you can use the Tuple<T1,T2> class in a : Dictionary<Tuple<T1,T2>, TItem>.
var coll = new Dictionary<Tuple<int,int>, AnyClass>();
coll.Add(new Tuple<int,int>(2, 3), new AnyClass("foo"));
coll.Add(new Tuple<int,int>(4, 2), new AnyClass("bar"));
var foo = coll[new Tuple<int,int>(2,3)];
var bar = coll[new Tuple<int,int>(4,2)];
If the syntax is too weird, you may wrap the class like this :
public class Dictionary2d<TKey1, TKey2, TItem> : Dictionary<Tuple<TKey1, TKey2>,TItem>
{
public void Add(TKey1 k1, TKey2, TItem item) {
this.Add(Tuple.Create(k1,k2), item);
}
public TItem this[TKey1 k1, TKey2 k2] {
get { return this[Tuple.Create(k1,k2)]; }
}
}
public class Program
{
static void Main() {
var coll = new Dictionary2d<int,int, AnyClass>();
coll.Add(2, 3, new AnyClass("foo"));
coll.Add(4, 2, new AnyClass("bar"));
var foo = coll[2,3];
var bar = coll[4,2];
}
}
The benefits of using Tuple class, is that the equality and hashcode comparison is natively handled, so even if it's a class, two differents instances of tuple with same values will be considered equals.
It sounds like you want a Dictionary<int, T>.
You can implement this Set<T> by storing its data in a private variable of type Dictionary<int, Dictionary<int, T>>.
You can then store using
public void Add(int key1, int key2, T value)
{
_storage[key1][key2] = value;
}
Related
Imagine this scenario: I need to manipulate (add, search and delete) items from a list of objects of type Book.
class Book{
int Id {get; set;}
string Title {get; set;}
string Author {get; set;}
int Year {get; set;}
// more properties
}
Constriants:
Id should be unique within the collection of Books
Title should be unique within the collection of Books
What I have so far, a Dictionary<int, Book> that has Id as a key and Book as a value. But in this case, If I want to add a new book to the dictionary I have to loop through all the values to check whether the Title is duplicate or not.
I start thinking about creating a HashSet only for Titles or having a second dictionary Dictionary<string, Book> that has Title as a key.
Any suggestion How to handle this scenario?
Edit:
As #David mentioned, I forgot to tell that my main concern here is performance. I want to lookup objects by Id and Title in the fastest way (O(1)).
You might use Tuple as the key:
var collection = new Dictionary<Tuple<int, string>, Book> (...);
var key = new Tuple<int, string>(1, "David"); // <<-----------
if(!collection.ContainsKey(key))
collection [key] = new Book(...);
Note that Tuple has its built in Equals() to make your life easier.
Update:
#AustinWBryan mentioned using ValueTuples (C# 7.0 feature) to replace Tuple, highly recommended. For more info about ValueTuples, refer to this link.
To ensure that both sides of the composite key are also unique a tuple won't cut it. Instead make your own key that checks for this in the equality checker.
public struct CompositeKey<T1, T2> : IEquatable<CompositeKey<T1, T2>>
{
private static readonly EqualityComparer<T1> t1Comparer = EqualityComparer<T1>.Default;
private static readonly EqualityComparer<T2> t2Comparer = EqualityComparer<T2>.Default;
public T1 Key1;
public T2 Key2;
public CompositeKey(T1 key1, T2 key2)
{
Key1 = key1;
Key2 = key2;
}
public override bool Equals(object obj) => obj is CompositeKey<T1, T2> && Equals((CompositeKey<T1, T2>)obj);
public bool Equals(CompositeKey<T1, T2> other)
{
return t1Comparer.Equals(Key1, other.Key1)
&& t2Comparer.Equals(Key2, other.Key2);
}
public override int GetHashCode() => Key1.GetHashCode();
}
So the dictionary works on buckets. It puts all the keys into buckets based on the hash code generated by GetHashCode(). Then it searches that bucket using a for loop over Equals(). The idea is that buckets should be as small as possible (ideally one item).
So we can control when a key will match, and how many buckets/items there are by controlling the hash code. If we return a constant hash code like 0, then everything is in the same bucket and it's down to the equality method to compare every item.
This comparer only returns the hash of the first key item. Assuming the first key item should be unique this is enough. Each bucket should still be one item, and when doing a lookup (that uses the full equals method) that's when the second key is also checked to ensure the type is the same value.
If you want to use ValueTuple as the key type you can pass in a custom comparer to the dictionary to achieve the same effect.
public class CompositeValueTupleComparer<T1, T2> : IEqualityComparer<(T1, T2)>
{
private static readonly EqualityComparer<T1> t1Comparer = EqualityComparer<T1>.Default;
private static readonly EqualityComparer<T2> t2Comparer = EqualityComparer<T2>.Default;
public bool Equals((T1, T2) x, (T1, T2) y) =>
t1Comparer.Equals(x.Item1, y.Item1) && t2Comparer.Equals(x.Item2, y.Item2);
public int GetHashCode((T1, T2) obj) => obj.Item1.GetHashCode();
}
new Dictionary<(int, string), Book>(new CompositeValueTupleComparer<int, string>());
It seems like both the ID and Name are going to be unique, as in, you shouldn't be able to use the same ID twice, regardless if the name has been used already. Otherwise, we'd end up with dict[3] referring to two different values.
Tuples or structs can't give that behavior, and still require you to loop. What you should instead do, is use a class similar to the one I've created:
public class TwoKeyDictionary<TKey1, TKey2, TValue>
{
public readonly List<TKey1> firstKeys = new List<TKey1>();
public readonly List<TKey2> secondKeys = new List<TKey2>();
public readonly List<TValue> values = new List<TValue>();
public void Add(TKey1 key1, TKey2 key2, TValue value)
{
if (firstKeys.Contains(key1)) throw new ArgumentException();
if (secondKeys.Contains(key2)) throw new ArgumentException();
firstKeys.Add(key1);
secondKeys.Add(key2);
values.Add(value);
}
public void Remove(TKey1 key) => RemoveAll(firstKeys.IndexOf(key));
public void Remove(TKey2 key) => RemoveAll(secondKeys.IndexOf(key));
private void RemoveAll(int index)
{
if (index < 1) return;
firstKeys.RemoveAt(index);
secondKeys.RemoveAt(index);
values.RemoveAt(index);
}
public TValue this[TKey1 key1]
{
get
{
int index = firstKeys.IndexOf(key1);
if (index < 0) throw new IndexOutOfRangeException();
return values[firstKeys.IndexOf(key1)];
}
}
public TValue this[TKey2 key2]
{
get
{
int index = secondKeys.IndexOf(key2);
if (index < 0) throw new IndexOutOfRangeException();
return values[secondKeys.IndexOf(key2)];
}
}
}
And then you can use it like this:
var twoDict = new TwoKeyDictionary<int, string, float>();
twoDict.Add(0, "a", 0.5f);
twoDict.Add(2, "b", 0.25f);
Console.WriteLine(twoDict[0]); // Prints "0.5"
Console.WriteLine(twoDict[2]); // Prints "0.25"
Console.WriteLine(twoDict["a"]); // Prints "0.5"
Console.WriteLine(twoDict["b"]); // Prints "0.25"
twoDict.Add(0, "d", 2); // Throws exception: 0 has already been added, even though "d" hasn't
twoDict.Add(1, "a", 5); // Throws exception: "a" has already been added, even though "1" hasn't
The TwoKeyDictionary would need to implement ICollection, IEnumerable, etc., to do the full behavior stuff
I am trying to build a dictionary where the key is a property of the value object. However I would like to construct the value object in the dictionary's add method. Is there a way to do this without using an intermediate variable?
For example I would like to do the following, but of course the key value isn't available when needed.
Dictionary<int,SomeComplexObject> dict = new Dicionary<int,SomeComplexObject>{
{someComplexObject.Key, new SomeComplexObject {Key = 1, Name = "FooBar"},
{someComplexObject.Key, new SomeComplexObject {Key = 2, Name = "FizzBang"}
};
Do I have to do it this ugly way:
Dictionary<int,SomeComplexObject> dict = new Dicionary<int,SomeComplexObject>();
SomeComplexObject value1 = new SomeComplexObject{Key=1,Name = "FooBar"};
dict.Add(value1.Key,value1);
SomeComplexObject value2 = new SomeComplexObject{Key=2,Name = "FizzBang"};
dict.Add(value.Key,value2);
I don't think this is the same question as
How to use an object's identity as key for Dictionary<K,V>
because I am not asking specifically about the key of a dictionary but if there is a way to have access to a objects property when the object is not being created until later in the methods parameter list.
I don't think an extension method (as proposed in comments) is really what you want here, as it's only a partial solution. I.e. you would have to write a new extension method for each dictionary value type you wanted to use, which negates the whole point of asking for a general solution.
Instead, it seems to me that you probably just want to subclass the Dictionary<TKey, TValue> type to add your own custom behavior. You can do this just once, in a general-purpose way, so that you can provide a delegate for each type you expect to have to use this way.
That would look something like this:
class KeyExtractorDictionary<TKey, TValue> : Dictionary<TKey, TValue>
{
private readonly Func<TValue, TKey> _extractor;
public KeyExtractorDictionary(Func<TValue, TKey> extractor)
{
_extractor = extractor;
}
public void Add(TValue value)
{
Add(_extractor(value), value);
}
}
You would use it something like this:
class Data
{
public int Key { get; }
public string Name { get; }
public Data(int key, string name)
{
Key = key;
Name = name;
}
}
class Program
{
static void Main(string[] args)
{
KeyExtractorDictionary<int, Data> dictionary =
new KeyExtractorDictionary<int, Data>(d => d.Key)
{
new Data(1, "FooBar"),
new Data(2, "FizzBang")
};
}
}
(I used Data as the value type type, instead of T as you seem to have used in your question, to avoid confusing the type name with a generic type parameter.)
In this way, you only have to write the class once, regardless of how many different types you might want to use for this type of dictionary. You can then pass the class constructor the key extractor delegate appropriate for the current value type of the dictionary.
Note that doing it this way, you also can take advantage of C#'s collection initializer syntax. Since your new type has an Add() method that takes just the value for each dictionary entry, the compiler will translate a collection initializer into the correct calls to add each object to the dictionary.
This allows for a dictionary in which you can still retrieve objects solely by the key value (using a custom comparer would require an instance of the value type with the same key you're looking for), while still addressing the broader concerns of not having to specify the key explicitly when adding objects, and of generality and reuse.
You can try an extension method, which is less invasive:
public static void AddByKey<TKey, T>(this Dictionary<TKey, T> dictionary, T item)
{
dictionary.Add(item.Key, item);
}
But to really do this correctly you also need an interface to protect you against types without the Key property:
public interface ItemWithKey<TKey>
{
TKey Key { get; }
}
public static void AddByKey<TKey, T>(this Dictionary<TKey, T> dictionary, T item)
where T : ItemWithKey<TKey>
{
dictionary.Add(item.Key, item);
}
I don't have a compiler in my hands right now, I cannot test this code so minor errors may have slipped in. I hope you get the idea and usefulness if you have those cases a lot in your code. Otherwise, I'd advise to go with the ugly working code you already have.
You can use the ToDictionary() extension method to solve this issue. Here is a complete example that can be run in LINQPad.
void Main()
{
Dictionary<int, SomeComplextObject> dict = new List<SomeComplextObject>{
{new SomeComplextObject {Key = 1, Name = "FooBar"}},
{new SomeComplextObject {Key = 2, Name = "FizzBangr"}}
}.ToDictionary(k =>k.Key);
//Dump Dictionary to LINQPad's result window.
dict.Dump();
}
public class SomeComplextObject{
public int Key { get; set; }
public string Name {get;set;}
}
I would like to propose a different slightly different way of going about this, it's similar to #pid 's method but instead of an interface uses a linq expression. First built your list of objects, then use an extension method to add them to your dictionary in a single simple step. In my mind this is also a little more intuitive to read, your program would look like:
class Program
{
static void Main(string[] args)
{
List<SomeComplexObject> toAdd = new List<SomeComplexObject>() {
new SomeComplexObject(1,"FooBar"),
new SomeComplexObject(2,"FizzBang")
};
var dict = new Dictionary<int,SomeComplexObject>();
dict.AddByKey(toAdd, item => item.Key);
}
}
Where AddByKey is an extension method that uses linq to basically pass a reference to that property and would look like this:
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
public static class DictionaryExtensions
{
/// <summary>
/// This extension method was built for when you want to add a list of items to a dictionary as the values, and you want to use one of those
/// items' properties as the key. It uses LINQ to check by property reference.
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
/// <param name="dict"></param>
/// <param name="targets"></param>
/// <param name="propertyToAdd"></param>
public static void AddByKey<TKey, TValue>(this Dictionary<TKey, TValue> dict, IEnumerable<TValue> targets, Expression<Func<TValue, TKey>> propertyToAdd)
{
MemberExpression expr = (MemberExpression)propertyToAdd.Body;
PropertyInfo prop = (PropertyInfo)expr.Member;
foreach (var target in targets)
{
var value = prop.GetValue(target);
if (!(value is TKey))
throw new Exception("Value type does not match the key type.");//shouldn't happen.
dict.Add((TKey)value, target);
}
}
}
And if you wanted to simplify the calling code even further, instead of returning void, you could have that extension method return the originally passed dictionary, and then your calling code could be collapsed to:
var dict = new Dictionary<int,SomeComplexObject>().AddByKey(toAdd, item => item.Key);
I'd like to create a Dictionary object, with string Keys, holding values which are of a generic type. I imagine that it would look something like this:
Dictionary<string, List<T>> d = new Dictionary<string, List<T>>();
And enable me to add the following:
d.Add("Numbers", new List<int>());
d.Add("Letters", new List<string>());
I know that I can do it for a list of strings, for example, using this syntax:
Dictionary<string, List<string>> d = new Dictionary<string, List<string>>();
d.Add("Key", new List<string>());
but I'd like to do it for a generic list if possible...
2 questions then:
Is it possible?
What's the syntax?
EDIT: Now I've reread the question...
You can't do this, but a custom collection would handle it to some extent. You'd basically have a generic Add method:
public void Add<T>(string key, List<T> list)
(The collection itself wouldn't be generic - unless you wanted to make the key type generic.)
You couldn't extract values from it in a strongly typed manner though, because the compiler won't know which type you've used for a particular key. If you make the key the type itself, you end with a slightly better situation, but one which still isn't supported by the existing collections. That's the situation my original answer was responding to.
EDIT: Original answer, when I hadn't quite read the question correctly, but which may be informative anyway...
No, you can't make one type argument depend on another, I'm afraid. It's just one of the things one might want to express in a generic type system but which .NET's constraints don't allow for. There are always going to be such problems, and the .NET designers chose to keep generics relatively simple.
However, you can write a collection to enforce it fairly easily. I have an example in a blog post which only keeps a single value, but it would be easy to extend that to use a list.
Would something like this work?
public class GenericDictionary
{
private Dictionary<string, object> _dict = new Dictionary<string, object>();
public void Add<T>(string key, T value) where T : class
{
_dict.Add(key, value);
}
public T GetValue<T>(string key) where T : class
{
return _dict[key] as T;
}
}
Basically it wraps all the casting behind the scenes for you.
How about Dictionary<string, dynamic>? (assuming you're on C# 4)
Dictionary<string, dynamic> Dict = new Dictionary<string, dynamic>();
Source: https://stackoverflow.com/a/5038029/3270733
I prefer this way of putting generic types into a collection:
interface IList
{
void Add (object item);
}
class MyList<T> : List<T>, IList
{
public void Add (object item)
{
base.Add ((T) item); // could put a type check here
}
}
class Program
{
static void Main (string [] args)
{
SortedDictionary<int, IList>
dict = new SortedDictionary<int, IList> ();
dict [0] = new MyList<int> ();
dict [1] = new MyList<float> ();
dict [0].Add (42);
dict [1].Add ("Hello"); // Fails! Type cast exception.
}
}
But you do lose the type checks at compile time.
I came to a type safe implementation using ConditionalWeakTable.
public class FieldByType
{
static class Storage<T>
where T : class
{
static readonly ConditionalWeakTable<FieldByType, T> table = new ConditionalWeakTable<FieldByType, T>();
public static T GetValue(FieldByType fieldByType)
{
table.TryGetValue(fieldByType, out var result);
return result;
}
public static void SetValue(FieldByType fieldByType, T value)
{
table.Remove(fieldByType);
table.Add(fieldByType, value);
}
}
public T GetValue<T>()
where T : class
{
return Storage<T>.GetValue(this);
}
public void SetValue<T>(T value)
where T : class
{
Storage<T>.SetValue(this, value);
}
}
It can be used like this:
/// <summary>
/// This class can be used when cloning multiple related objects to store cloned/original object relationship.
/// </summary>
public class CloningContext
{
readonly FieldByType dictionaries = new FieldByType();
public void RegisterClone<T>(T original, T clone)
{
var dictionary = dictionaries.GetValue<Dictionary<T, T>>();
if (dictionary == null)
{
dictionary = new Dictionary<T, T>();
dictionaries.SetValue(dictionary);
}
dictionary[original] = clone;
}
public bool TryGetClone<T>(T original, out T clone)
{
var dictionary = dictionaries.GetValue<Dictionary<T, T>>();
if (dictionary == null)
{
clone = default(T);
return false;
}
return dictionary.TryGetValue(original, out clone);
}
}
See also this question where the type of the values is stored in as a generic parameter of the keys.
We're using lots of reflection to create an extensible administration tool. We needed a way to register items in the global search in the module definition. Each search would return results in a consistent way, but each one had different dependencies. Here's an example of us registering search for a single module:
public void ConfigureSearch(ISearchConfiguration config)
{
config.AddGlobalSearchCallback<IEmploymentDataContext>((query, ctx) =>
{
return ctx.Positions.Where(p => p.Name.Contains(query)).ToList().Select(p =>
new SearchResult("Positions", p.Name, p.ThumbnailUrl,
new UrlContext("edit", "position", new RouteValueDictionary(new { Id = p.Id }))
));
});
}
In the background during module registration, we iterate over every module and add the Func to a SearchTable with an instance of:
public class GenericFuncCollection : IEnumerable<Tuple<Type, Type, Object>>
{
private List<Tuple<Type, Type, Object>> objects = new List<Tuple<Type, Type, Object>>();
/// <summary>
/// Stores a list of Func of T where T is unknown at compile time.
/// </summary>
/// <typeparam name="T1">Type of T</typeparam>
/// <typeparam name="T2">Type of the Func</typeparam>
/// <param name="func">Instance of the Func</param>
public void Add<T1, T2>(Object func)
{
objects.Add(new Tuple<Type, Type, Object>(typeof(T1), typeof(T2), func));
}
public IEnumerator<Tuple<Type, Type, object>> GetEnumerator()
{
return objects.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return objects.GetEnumerator();
}
}
Then when we finally call it, we do it with reflection:
var dependency = DependencyResolver.Current.GetService(search.Item1);
var methodInfo = search.Item2.GetMethod("Invoke");
return (IEnumerable<SearchResult>)methodInfo.Invoke(search.Item3, new Object[] { query, dependency });
I didn't find what I was looking for here but after reading I think it might be what is being asked for so an attempt to answer.
The problem is that when you use Dictionary it is a closed constructed type and all elements must be of the TValue type. I see this question in a number of places without a good answer.
Fact is that I want indexing but each element to have a different type and based on the value of TKey we already know the type. Not trying to get around the boxing but trying to simply get more elegant access something like DataSetExtensions Field. And don't want to use dynamic because the types are known and it is just not wanted.
A solution can be to create a non generic type that does not expose T at the class level and therefore cause the TValue part of the dictionary to be closed constructed. Then sprinkle in a fluent method to help initialization.
public class GenericObject
{
private object value;
public T GetValue<T>()
{
return (T)value;
}
public void SetValue<T>(T value)
{
this.value = value;
}
public GenericObject WithValue<T>(T value)
{
this.value = value;
return this;
}
}
class Program
{
static void Main(string[] args)
{
Dictionary<string, GenericObject> dict = new Dictionary<string, GenericObject>();
dict["mystring"] = new GenericObject().WithValue<string>("Hello World");
dict["myint"] = new GenericObject().WithValue<int>(1);
int i = dict["myint"].GetValue<int>();
string s = dict["mystring"].GetValue<string>();
}
}
Other posibility it's to use the variable dynamic.
For example:
Dictionary<string, List<dynamic>> d = new Dictionary<string, List<dynamic>>();
d.Add("Key", new List<dynamic>());
the variable dynamic resolve the type on runtime.
No, but you can use object instead of generic type.
Long answer:
The current version of C# will not allow you to make entries of generic type in a dictionary. Your options are either a) create a custom class that is the same as a dictionary except allow it to accept generic types, or b) make your Dictionary take values of type object. I find option b to be the simpler approach.
If you send lists of specific types, then when you go to process the lists you will have to test to see what kind of list it is. A better approach is to create lists of objects; this way you can enter integers, strings, or whatever data type you want and you don't necessarily have to test to see what type of object the List holds. This would (presumably) produce the effect you're looking for.
Here is a short console program that does the trick:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace dictionary
{
class Program
{
static void Main(string[] args)
{
Dictionary<string, object> dic = new Dictionary<string, object>();
var lstIntList = new List<object>();
var lstStrings = new List<object>();
var lstObjects = new List<object>();
string s = "";
lstIntList.Add(1);
lstIntList.Add(2);
lstIntList.Add(3);
lstStrings.Add("a");
lstStrings.Add("b");
lstStrings.Add("c");
dic.Add("Numbers", lstIntList);
dic.Add("Letters", lstStrings);
foreach (KeyValuePair<string, object> kvp in dic)
{
Console.WriteLine("{0}", kvp.Key);
lstObjects = ((IEnumerable)kvp.Value).Cast<object>().ToList();
foreach (var obj in lstObjects)
{s = obj.ToString(); Console.WriteLine(s);}
Console.WriteLine("");
}
Console.WriteLine("");
Console.WriteLine("press any key to exit");
Console.ReadKey();
}//end main
}
}
One of the way is to create a Dictionary value with type "object" like:
Dictionary<string, object> d = new Dictionary<string, object>();
So, here object datatype is used as a generic datatype, you can put anything in this as a value.
Or it's possible to use generic Type like this
public static void SafeUpdateInDictionary<T, L>(T DictionaryToBeUpdated, string Key, L Value) where T : Dictionary<string, L>
{
if (DictionaryToBeUpdated != null)
{
if(Value != null)
{
if (!DictionaryToBeUpdated.ContainsKey(Key))
DictionaryToBeUpdated.Add(Key, Value);
else
DictionaryToBeUpdated[Key] = Value;
}
}
}
Imagine I have class like this:
class MyKey : IComparable<MyKey> {
public int Key { get; private set; }
public MyKey(int key) { Key = key; }
public int CompareTo(MyKey that) {
return that.Key - this.Key;
}
}
Furthermore, I have a generic wrapper class like this:
class MyListWrapper<T> where T : MyKey
{
private List<T> list;
public MyListWrapper(IEnumerable<T> items)
{
list = new List<T>(items);
list.Sort();
}
public int Search(T searchKey)
{
return list.BinarySearch(searchKey);
}
}
This allows people to store custom class inheriting from MyKey, and it works perfectly fine. However, it would also make sense to be able to search using a MyKey as we know T is a MyKey, and the list is sorted using MyKey's Key:
public int Search(MyKey searchKey)
{
return list.BinarySearch(searchKey); // Does not compile!
}
However, this doesn't compile, since BinarySearch takes a T (T could be any custom class).
Neither does it work, if I provide the comparer. Imagine MyKey wasn't comparable, but I made a custom comparer that used Key instead. I could use it when sorting and when searching.
Is is possible to search the list using MyKey somehow? I don't like storing the list as List<MyKey> and cast the values when I use them (that defeats the purpose of the generic list). I can't cast the list of type List<T> to List<MyKey> either.
You can create a wrapper class which inherits from MyNamedKey or create new instance of MyNamedKey itself just to search the item.
var mySearchKey = new MyKey { Key = 2 };
var index = list.BinarySearch(new MyNamedKeyWrapper(mySearchKey));
class MyNamedKeyWrapper : MyNamedKey
{
public MyNamedKeyWrapper(MyKey key)
{
this.Key = key.Key;
}
}
This will help you to maintain O(log n) while adding small allocation cost.
Or if you prefer to use brittle reflection, you can.. Get the instance of underlying array and cast it to MyKey[] (This works because arrays are covariant) and use Array.BinarySearch.
var array = (MyKey[])list.GetType()
.GetField("_items", BindingFlags.Instance | BindingFlags.NonPublic)
.GetValue(list);
var index = Array.BinarySearch(array, mySearchKey);
Edit: Since you don't know the most derived type, if you constraint new() with your generic parameter, you can achieve what you're looking for
class MyListWrapper<T> where T : MyKey, new()
{
private readonly List<T> list;
public MyListWrapper(IEnumerable<T> items)
{
list = new List<T>(items);
list.Sort();
}
public int Search(MyKey searchKey)
{
T dummyKey = new T() { Key = searchKey.Key };
return list.BinarySearch(dummyKey);
}
}
Linq is what you're after!
First, make sure you have System.Linq referenced in your usings.
Then you can use the following code to get all matching list items:
IEnumerable<MyNamedKey> found = list.Where(l => l.Key == 2);
To get a single item, use:
MyNamedKey found = list.FirstOrDefault(l => l.Key == 2);
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Bidirectional 1 to 1 Dictionary in C#
Im curious if a datastructure exists in the standard .net libraries that can represent a 1-1 relationship, such as the following
1-a
4-b
6-c
5-d
Where I can say:
thisstructure[1] // returns "a"
thisstructure.GetKey["d"] // return 5
I understand all keys would have to be unique, does anything similar exist?
Thanks!
Yes- it's called KeyedCollection. It is intended to be subclassed and provides indexed access as well as access by a property derived from the added item. I usually make a generic subclass:
public class GenericKeyedCollection<TKey, TValue> : KeyedCollection<TKey, TValue> {
private readonly Func<TValue, TKey> _keyGenerator;
public GenericKeyedCollection(Func<TValue, TKey> keyGenerator) {
_keyGenerator = keyGenerator;
}
protected override int GetKeyForItem(TValue item)
{
return _keyGenerator(item);
}
}
To use it:
var myCollection = new GenericKeyedCollection<String, Car>(c=>c.Model);
myCollection.Add(new Car("Ford", "Mustang"));
var byIndex = myCollection[0];
var byModel = myCollection["Mustang"];
The only caveat is that the derived property (the "key") mustn't change after the item has been added.
If your key is not a property of the value, then you can use a Tuple<T1, T2> to combine the key and value:
var myCollection = new GenericKeyedCollection<String, Tuple<String, Car>>(t=>t.Item1);
myCollection.Add(new Tuple<String, Car>("Foo", Car("Ford", "Mustang")));
var byIndexCar = myCollection[0].Item2;
var byItem1Car = myCollection["Foo"].Item2;
Could this method fit your needs?
public static class Extensions
{
public static TKey GetKey<TKey, TValue>(this Dictionary<TKey, TValue> dict, TValue value)
{
int index = dict.Values.ToList().IndexOf(value);
if (index == -1)
{
return default(TKey); //or maybe throw an exception
}
return dict.Keys.ToList()[index];
}
}
You could then use it like so:
Dictionary<int, char> dict = new Dictionary<int, char>();
dict.Add(1, 'a');
dict.Add(4, 'b');
dict.Add(6, 'c');
dict.Add(5, 'd');
Console.WriteLine(dict.GetKey('d')); //5
The Dictionary....or IDictionary interface is the closest I can think of to what you want. It doesn't have quite so simple a searching operation, in that searching on a value can return the key, but I do know you can search on a key to get a value. providing functionality for the reverse in a custom extended class wouldn't be difficult at all.
MSDN IDictionary page