What is the collection equivalent of a multi-dimensional array? - c#

I've got a group of data that looks like this:
001 001 One
001 002 Two
001 003 Three
002 001 One
002 002 Two
002 003 Three
...
Now, certainly, I could create an array of string[x][y] = z, but this array has to be resizable, and i'd prefer to use the string representations of the indexers than convert to numeric. The reason is that i will need to look up the data by string, and i don't see the point in needless string->number conversions.
My first thought was this:
Dictionary<string, Dictionary<string, string>> data;
data = new Dictionary<string, Dictionary<string, string>>();
Dictionary<string, string> subdata = Dictionary<string, string>();
subdata.Add(key, string);
data.add(key2, subdata);
and this works, but is somewhat cumbersome. It also feels wrong and kludgy and not particularly efficient.
So what's the best way to store this sort of data in a collection?
I also thought of creating my own collection class, but I'd rather not if I don't have to. I'd rather just use the existing tools.

This is pretty common request, and most people end up writing some variation of a Tuple class. If you're using ASP.Net, you can utilize the Triple class that's already available, otherwise, write something like:
public class Tuple<T, T2, T3>
{
public Tuple(T first, T2 second, T3 third)
{
First = first;
Second = second;
Third = third;
}
public T First { get; set; }
public T2 Second { get; set; }
public T3 Third { get; set; }
}
There's a generic three-tuple class, so you can create a new List<Tuple<string, string, string>>() and create your tuples and add them. Expand on that basic class with some indexing functionality and you're up up and away.
Edit: A list with a dictionary doesn't seem like the correct approach, because each dictionary is only holding one value. There is no multi-entry relationship between the key and values - there is simply one multi-part key and one associated value. The data is equivalent to a database row (or tuple!).
Edit2: Here's an indexable list class you could use for convenience.
public class MyTupleList : List<Tuple<string, string, string>>
{
public Tuple<string, string, string> this[string first, string second]
{
get
{
return (this.Find(x => x.First == first && x.Second == second));
}
set
{
this[first, second] = value;
}
}
}

I think this really depends on what you are modelling here. If you're planning to use an object-oriented approach, you shouldn't be thinking of these as arbitrary items inside a data structure.
I'm guessing from looking at this that the first two columns are serving as a "key" for the other items. Define a simple struct, and create a dictionary of like so:
struct Key {
public int Val1 { get; set; }
public int Val2 { get; set; }
}
....
Dictionary<Key, string> values;
Obviously Key and the items inside it should be mapped to something closer to what you are representing.

Given a suitable Pair<A,B> class*, left as an exercise for the reader, you could use a Dictionary<Pair<string, string>, string>.
* A class with equality and hash code overrides, nothing terribly hard.

Would a List<List<T>> work for you? Still kludgy, but better than dictionaries IMHO.
EDIT: What about a Dictionary<string,string> and mapping the two keys to a single string?
var data = new Dictionary<string,string>(StringComparer.Ordinal);
data[GetKey("002", "001")] = "One";
with
string GetKey(string a, string b) {
return a + "\0" + b;
}

List<List<string>> is really your best bet in this case. But I agree, it's kludgy. Personally, I would create a custom class that implements a two-dimensional indexer and maybe use a List<List<T>> internally.
For example:
public class DynamicTwoDimensonalArray<T>
{
private List<List<T>> Items = new List<List<T>>();
public T this[int i1, int i2]
{
get
{
return Items[i1][i2];
}
set
{
Items[i1][i2] = value;
}
}
}
This is a basic idea to get you going; clearly the setter needs to deal with bounds issues. But it's a start.
Edit:
No. As I said, I would prefer to index them by string. And they may not always be sequential (might have a missing number in the middle). - Mystere Man
Hmm... this is interesting. If that's the case, your best bet would be to create some sort of concatenation of the combination of the two indexers and use that as the key in a single-level dictionary. I would still use a custom class to make using the indexing easier. For example:
public class TwoDimensionalDictionary
{
private Dictionary<string, string> Items = new Dictionary<string, string>();
public string this[string i1, string i2]
{
get
{
// insert null checks here
return Items[BuildKey(i1, i2)];
}
set
{
Items[BuildKey(i1, i2)] = value;
}
}
public string BuildKey(string i1, string i2)
{
return "I1: " + i1 + " I2: " + i2;
}
}

If you are ever going to need to find z by given (x,y) (and not, for example, find all y by given x), then use this:
Dictionary<KeyValuePair<string, string>, string>
Otherwise, your dictionary is fine as is.

Related

Get and set value from bindinglist<T> with coordinates c#

I'm having trouble getting and setting the values of an item in a bindinglist with coordinates when the type vary.
For example, let's say I have three classes:
public class Client{
public string Name{ get; set; }
}
public class Debt{
public string AccountType{ get; set; }
public int DebtValue { get; set; }
}
public class Accounts{
public string Owner{ get; set; }
public int AccountNumber { get; set; }
public bool IsChekingAccount { get; set; }
}
and then, three bindinglists (imagine they are populated):
public BindingList<Client> listOne;
public BindingList<Debt> listTwo;
public BindingList<Accounts> listThree;
I'm trying to create an extension method that returns an Object with the value requested, or sets the value if it is provided.
public static Object GetValueByCoordinates(this IBindingList list, int x, int y) { /*some magic*/ }
public static Object SetValueByCoordinates(this IBindingList list, int x, int y, Object value) { /*some other magic*/ }
So, for instance, I need to be able to set the value of the item (2,3) in the listThree, and the value (1,1) in listTwo:
listThree.SetValueByCoordinates(2,3,false);
listThree.SetValueByCoordinates(1,1,"My self");
or get the value (1,1) and (2,2) from listOne and listTwo:
string result = listOne.GetValueByCoordinates(1,1).ToString();
intresult = Convert.ToInt32(listOne.GetValueByCoordinates(1,1));
How would you achieve such behavior? i was thinking of using reflection, but I know little to nothing about it.
please note that the methods MUST be called that way, so using something like this must be avoided
public static Object GetValueByCoordinates<T>(this BindingList<T> list, int x, int y) { /*some magic*/ }
Any help will be appreciated.
As mentioned, I am very skeptical that the approach you're asking for help with is likely to be the best or most appropriate way to address whatever the broader issue you're trying to solve is. It can be done (and without very much difficulty), but the resulting code is difficult to maintain, error-prone, and not very readable (which leads to the first two problems).
That said, there are lots of different ways to implement the specific behavior you're asking for. And even if this is not the best way to solve your current problem, the basic techniques are useful to know for other types of problems. With that in mind, here are two of the most obvious ways you might address your problem.
Manually configure a mapping from indexes to getters and setters:
IMHO this is the most preferable way. Not because it's elegant or easy to extend, but specifically because it's not either of those things. Requiring code maintainers to explicitly create the data structure elements to support each type and property that you want to handle will discourage a proliferation of this technique for other related problems, and even for the current problem. It could even encourage someone to spend a little more time thinking about the broader problem so as to find a better strategy.
This approach does have the advantage that it is reasonably performant. Because the code is generated at compile time, the only real overhead is the boxing that occurs for value types. There's some casting but for the reference types that overhead should be practically unmeasurable, and even the boxing overhead may not show up on a profile, depending on how intensively this code might be used.
This particular solution looks like this:
static class ManualIndexedProperty
{
public static void SetValueByCoordinates(this IBindingList list, int x, int y, object value)
{
object o = list[x];
_typeToSetter[o.GetType()][y](o, value);
}
public static object GetValueByCoordinates(this IBindingList list, int x, int y)
{
object o = list[x];
return _typeToGetter[o.GetType()][y](o);
}
private static readonly Dictionary<Type, Func<object, object>[]> _typeToGetter =
new Dictionary<Type, Func<object, object>[]>()
{
{
typeof(Client),
new Func<object, object>[]
{
o => ((Client)o).Name
}
},
{
typeof(Debt),
new Func<object, object>[]
{
o => ((Debt)o).AccountType,
o => ((Debt)o).DebtValue,
}
},
{
typeof(Accounts),
new Func<object, object>[]
{
o => ((Accounts)o).Owner,
o => ((Accounts)o).AccountNumber,
o => ((Accounts)o).IsChekingAccount,
}
},
};
private static readonly Dictionary<Type, Action<object, object>[]> _typeToSetter =
new Dictionary<Type, Action<object, object>[]>()
{
{
typeof(Client),
new Action<object, object>[]
{
(o1, o2) => ((Client)o1).Name = (string)o2
}
},
{
typeof(Debt),
new Action<object, object>[]
{
(o1, o2) => ((Debt)o1).AccountType = (string)o2,
(o1, o2) => ((Debt)o1).DebtValue = (int)o2,
}
},
{
typeof(Accounts),
new Action<object, object>[]
{
(o1, o2) => ((Accounts)o1).Owner = (string)o2,
(o1, o2) => ((Accounts)o1).AccountNumber = (int)o2,
(o1, o2) => ((Accounts)o1).IsChekingAccount = (bool)o2,
}
},
};
}
Two dictionaries are declared, one each for setting and getting property values. The dictionaries map the element object's type to an array of delegate instances to perform the actual work. Each delegate instance references an anonymous method which has been hand-coded to perform the necessary operation.
One major advantage to this approach is that it is explicit and obvious what index corresponds to what property for each type.
This approach will be tedious and time-consuming to set up if you are dealing with any significant number of types and/or properties. But IMHO that's a good thing. As I noted above, hopefully the pain of this approach can help convince someone to abandon the idea of accessing the properties by index altogether. :)
If this kind of tedium is unacceptable and yet you still insist on the indexed-property-access approach, then you can in fact use reflection as an alternative…
Use reflection to access the properties:
This technique is more dynamic. Once implemented, it works for any type object without modification, and does not require additional work to support new types.
One major disadvantage is that in order to produce consistent, predictable results, it sorts the properties by name. This ensures that changes in the C# compiler and/or CLR won't break the code, but it means you can't add or remove properties from a type without updating the code that is accessing those properties by index.
In my demo usage code (see further below), I address this maintenance issue by declaring enum types that provide int values for property names. This would be a good way to help reduce the maintenance overhead if the code is actually referring to the properties with literal index values.
However, it's possible your scenario involves dynamically accessing the property values by index, e.g. in a serialization scenario or similar. In that case, you will also need to add something that can remap or otherwise deal with changes in the index values should properties be added or removed to the types.
Frankly, either way this issue of the types indexes changing is one big reason I'd strongly recommend against this indexed access to properties in the first place. But again, if you insist…
static class ReflectionIndexedProperty
{
public static void SetValueByCoordinates(this IBindingList list, int x, int y, object value)
{
object o = list[x];
GetProperty(o, y).SetValue(o, value);
}
public static object GetValueByCoordinates(this IBindingList list, int x, int y)
{
object o = list[x];
return GetProperty(o, y).GetValue(o);
}
private static PropertyInfo GetProperty(object o, int index)
{
Type type = o.GetType();
PropertyInfo[] properties;
if (!_typeToProperty.TryGetValue(type, out properties))
{
properties = type.GetProperties();
Array.Sort(properties, (p1, p2) => string.Compare(p1.Name, p2.Name, StringComparison.OrdinalIgnoreCase));
_typeToProperty[type] = properties;
}
return properties[index];
}
private static readonly Dictionary<Type, PropertyInfo[]> _typeToProperty = new Dictionary<Type, PropertyInfo[]>();
}
In this version, the code retrieves the array of PropertyInfo objects for a given type, sorts that array by name, retrieves the appropriate PropertyInfo object for the given index, and then uses that PropertyInfo object to set or get the property value, as appropriate.
Reflection incurs a significant run-time performance overhead. This particular implementation mitigates some of that overhead by caching the sorted arrays of PropertyInfo objects. That way, they only need to be created once, the first time the code has to handle an object of the given type.
Demo code:
As I mentioned, to make it easier to compare the two approaches without having to go to each method call and hand-change an integer literal used for the call, I created some simple enum types to represent the property indexes. I also wrote some code to initialize some lists that could be tested.
Note: one very important thing to point out is that in your question you were not very consistent about how you were indexing the properties. In my code example, I have chose to stick with a 0-based index (consistent with the natural indexing used in C# arrays and other collections). You can of course use a different base (e.g. 1-based indexing), but you will need to make sure you are entirely consistent throughout the code (including subtracting 1 from the passed-in index when actually indexing an array).
My demo code looks like this:
class Program
{
static void Main(string[] args)
{
BindingList<Client> listOne = new BindingList<Client>()
{
new Client { Name = "ClientName1" },
new Client { Name = "ClientName2" },
new Client { Name = "ClientName3" },
};
BindingList<Debt> listTwo = new BindingList<Debt>()
{
new Debt { AccountType = "AccountType1", DebtValue = 29 },
new Debt { AccountType = "AccountType2", DebtValue = 31 },
new Debt { AccountType = "AccountType3", DebtValue = 37 },
};
BindingList<Accounts> listThree = new BindingList<Accounts>()
{
new Accounts { Owner = "Owner1", AccountNumber = 17, IsChekingAccount = false },
new Accounts { Owner = "Owner2", AccountNumber = 19, IsChekingAccount = true },
new Accounts { Owner = "Owner3", AccountNumber = 23, IsChekingAccount = true },
};
LogList(listThree);
listThree.SetValueByCoordinates(2, (int)AccountsProperty.IsChekingAccount, false);
listThree.SetValueByCoordinates(1, (int)AccountsProperty.Owner, "My self");
LogList(listThree);
string result1 = (string)listOne.GetValueByCoordinates(0, (int)ClientProperty.Name);
int result2 = (int)listTwo.GetValueByCoordinates(1, (int)DebtProperty.DebtValue);
LogList(listOne);
LogList(listTwo);
Console.WriteLine("result1: " + result1);
Console.WriteLine("result2: " + result2);
}
static void LogList<T>(BindingList<T> list)
{
foreach (T t in list)
{
Console.WriteLine(t);
}
Console.WriteLine();
}
}
Note that I use simple casting to convert from object to the specific type, both with setting property values and getting them. This is a much better approach than e.g. calling ToString() or Convert.ToInt32(); you know exactly what the type is supposed to be, and it's either an actual instance of that type (for reference types) or a boxed instance (for value types), and either way a cast does exactly what you need.
I also added ToString() overrides to your example classes to make it easier to see the output:
public class Client
{
public string Name { get; set; }
public override string ToString()
{
return "{" + Name + "}";
}
}
public class Debt
{
public string AccountType { get; set; }
public int DebtValue { get; set; }
public override string ToString()
{
return "{" + AccountType + ", " + DebtValue + "}";
}
}
public class Accounts
{
public string Owner { get; set; }
public int AccountNumber { get; set; }
public bool IsChekingAccount { get; set; }
public override string ToString()
{
return "{" + Owner + ", " + AccountNumber + ", " + IsChekingAccount + "}";
}
}
Finally, here are the enum declarations used:
Manual indexing:
enum ClientProperty
{
Name = 0
}
enum DebtProperty
{
AccountType = 0,
DebtValue = 1
}
enum AccountsProperty
{
Owner = 0,
AccountNumber = 1,
IsChekingAccount = 2,
}
Reflection/sorted by name:
enum ClientProperty
{
Name = 0
}
enum DebtProperty
{
AccountType = 0,
DebtValue = 1
}
enum AccountsProperty
{
AccountNumber = 0,
IsChekingAccount = 1,
Owner = 2,
}
Of course, these could both have been the same values. That is, while you don't have control over the sort order, once the property names are given, the manual version could have declared the manually-written lambdas in sorted-by-name order so that the same indexes would have worked either way. It doesn't matter too much what you decide to do; it just has to be consistent.
Final thoughts…
Have I mentioned yet how strongly I would recommend against building any significant amount of code around this technique? It's not at all clear what your actual bigger-picture problem you're trying to solve is, but there are just a lot of different ways for this to go wrong, and it is likely to lead to lots of hard-to-find, time-consuming-to-fix bugs in the code.
In terms of performance, the above should not be too bad as long as you are not executing the code in a tight loop for huge numbers of objects and property values. The manual (first) example in particular should be relatively fast. It is possible to achieve the generalized design of the reflection-based approach with the minimal overhead of the manual approach by using the Expression type. That's a bit more complicated, but would have the advantage that you can generate expressions dynamically that wind up being effectively the compiled-code implementation of the manual approach.

Is it common practice to use dictionary to check unique element in the list?

Say I have a list of objects, object Fruit. Fruit has a property Name. i.e. Fruit1.Name = "Apple", Fruit2.Name = "Orange", Fruit3.Name = "Apple", Fruit4.Name = "Melon"... etc
List<Fruit> Basket = {Fruit1, Fruit2, Fruit3, Fruit4, Fruit 5...... Fruit 100}.
I want to have a list of Unique Fruits, where every fruit in the list has unique name. I want to optimize for time.
I've seen some people do the following. Is this a best way?
public List<Fruit> GetUniqueFruits(List<Fruit> Basket)
{
Dictionary<string, Fruit> tempUniqueFruits = new Dictionary<string, Fruit>();
List<Fruit> uniqueFruits = new List<Fruit>();
foreach(var fruit in Basket)
{
if (!tempUniqueFruits.ContainsKey(fruit.Name)
{
tempUniqueFruits.Add(fruit.Name, fruit);
uniqueFruits.Add(fruit);
}
}
return uniqueFruits;
}
I hear dictionary lookup is very fast, so I guess maybe that's why this is used, but I want to know if there is a better way.
Thanks matt burland, i fixed the typo. ( coulnd't comment yet)
You can use an IEqualityComparer to clarify the code.
public List<Fruit> GetUniqueFruits(List<Fruit> Basket) {
var set = new HashSet<Fruit>(Basket, new FruitNameEqualityComparer());
return set.ToList();
}
public class Fruit {
public string Name { get; set; }
public DateTime RipeTime { get; set; }
}
class FruitNameEqualityComparer : IEqualityComparer<Fruit> {
public int Compare(Fruit a, Fruit b) {
return a.Name.CompareTo(b.Name);
}
public bool Equals(Fruit a, Fruit b) {
return a.Name.Equals(b.Name);
}
public int GetHashCode(Fruit f) {
return f.Name.GetHashCode();
}
}
Dictionary<T, U> is best used when you are mapping from keys to values, but if you are only interested in maintaining a set of unique values without any mappings, a HashSet<T> is specifically designed for that purpose.
A dictionary forces the code to make sure that it only contains unique keys, not values. So if you try to add another key that already exists it will throw an error. When wanting to grab a value you just have to get it by the key name which the dictionary does a lookup using a hash, which makes it very very fast. When wanting to search the list you have to iterate the whole list to find the one you want which can be slow as you are iterating the whole list.
A shorter way would be:
return Basket.GroupBy(f => f.Name).Select(grp => grp.First()).ToList();
although this might not keep the first item in Basket with the given name.
So if the names are the unique part of the object (i.e. the key) and the order of the items isn't important, then a Dictionary<string, Fruit> is a perfectly valid way to store them. Another option would be HashSet, but then you'd need to implement Equals and GetHashCode in your Fruit class (or create a IEqualityComparer<Fruit>).
But for you specific code, there are Linq statements you can use (like Lee's) which are efficient, but with your particular code, you don't need to keep create a list of unique items at the same time as you are building your dictionary (unless the order is important) because your can return tempUniqueFruits.Values.ToList()
Also, if you want to build the list of unique items (to preserve the order), then since you are not actually using the values in the dictionary, just the keys, you could use a HashSet<string> instead.

How do I create a Dictionary that holds different types in C#

I need some sort of way to store key/value pairs where the value can be of different types.
So I like to do:
int i = 12;
string s = "test";
double x = 24.1;
Storage.Add("age", i);
Storage.Add("name", s);
Storage.Add("bmi", x);
And later retrieve the values with:
int a = Storage.Get("age");
string b = Storage.Get("name");
double c = Storage.Get("bmi");
How should a Storage like this look like?
Thanks,
Erik
Well, you could use Dictionary<string, dynamic> in C# 4 / .NET 4 - but other than that, you can't do it with exactly the code shown because there's no type which is implicitly convertible to int, string and double. (You could write your own one, but you'd have to list each type separately.)
You could use Dictionary<string, object> but then you'd need to cast the results:
int a = (int) Storage.Get("age");
string b = (string) Storage.Get("name");
double c = (double) Storage.Get("bmi");
Alternatively, you could make the Get method generic:
int a = Storage.Get<int>("age");
// etc
You could declare a Dictionary containing just the type object and then cast your results; .e.g.
Dictionary<string, object> storage = new Dictionary<string,object>();
storage.Add("age", 12);
storage.Add("name", "test");
storage.Add("bmi", 24.1);
int a = (int)storage["age"];
string b = (string)storage["name"];
double c = (double)storage["bmi"];
However, this isn't that elegant. If you know you are always going to be storing age, name, bmi I would create an object to encapsulate those and store that instead. E.g.
public class PersonInfo
{
public int Age { get; set; }
public string Name { get; set; }
public double Bmi { get; set; }
}
And then use that insead of the Dictionary... e.g.
PersonInfo person1 = new PersonInfo { Name = "test", Age = 32, Bmi = 25.01 };
int age = person1.Age;
etc.
Why not use:
Dictionary<string, object>
You can create an extension method to cast them when you get them:
public static class DictionaryExcetions
{
public static T Get<T>(this Dictionary<string, object> instance, string name)
{
return (T)instance[name];
}
}
var age = dictionary.Get<int>("age");
Given that you don't want a strongly typed data collection then I would have thought a HashTable would be suitable for your situation. You could create an Extention method for this also, like another poster suggested for the Dictionary implementation.
E.g.
public static class StorageExtentions
{
public static T Get<T>(this Hashtable table, object key)
{
return (T) table[key];
}
}
Your code would then look like:
int i = 12;
string s = "test";
double x = 24.1;
Hashtable Storage = new Hashtable();
Storage.Add("age", i);
Storage.Add("name", s);
Storage.Add("bmi", x);
int a = Storage.Get<int>("age");
string b = Storage.Get<string>("name");
double c = Storage.Get<double>("bmi");
maybe it is an old question, but I am addressing the guys who come here to find the answer
if the value is not a fixed type one of the choices is using Hashtable
please look at the implementation of both Dictionary and Hashtable
public class Dictionary<TKey, TValue> : ICollection<KeyValuePair<TKey, TValue>>, IEnumerable<KeyValuePair<TKey, TValue>>, IEnumerable, IDictionary<TKey, TValue>, IReadOnlyCollection<KeyValuePair<TKey, TValue>>, IReadOnlyDictionary<TKey, TValue>, ICollection, IDictionary, IDeserializationCallback, ISerializable
{
...
}
public class Hashtable : ICollection, IEnumerable, IDictionary, ISerializable, IDeserializationCallback, ICloneable
{
...
}
as it gets more clear from above code snippets, both implement literally the same interfaces but in Hashtable there is no type on both key & value since both of them considered to be intrinsically objects, for example you can see from add method in Hashtable:
public virtual void Add(object key, object value);
so for the cases of not having fixed keys and/or values, I recommend using Hashtable, therefore you don't need to add extra extension methods or override default behavior of a dictionary any more.
Dictionary<string, object>
You can use a Dictionary<string,object> and then you can put anything you want into it. You would have to cast the results to the right type when you get them out though.
Looking at your example though you might want to consider whether a simple class to store the data might be more what you want and allow better type safety. It depends on whether you have a limited set of things to put in the class or if you do need the potentially unlimited/unknown storage of a dictionary.
Dictionary is clearly the quickest solution.
Another way could be to store a custom class in which you could store the actual value and the information regarding its type

How can I shorten List<List<KeyValuePair<string, string>>>?

I want to store an list of key value pair lists in a lightweight structure. This seems too cumbersome. What's better? Does List<Dictionary<string, string>> add much a overhead? What other options are available?
Consider using aliasing for shorthand:
namespace Application
{
using MyList = List<List<KeyValuePair<string, string>>>;
public class Sample
{
void Foo()
{
var list = new MyList();
}
}
}
Both List and Dictionary are pretty efficient, so I wouldn't think twice about using them. (Unless you're going to be storing a gazillion dictionaries in your list, but that's not very common.)
If you think that List<Dictionary<string, string>> is too much to type, you can say in your preamble
using LoDSS = System.Collections.Generic.List<System.Collections.Generic.Dictionary<string, string>>;
Note that this is just an alias no subclassing needed.
Dictionary< string, string> and List< KeyValuePair< string, string>> could both be fine, depending on what data you wanted to pass around. Also, if you are going to use the same long type all over the place you could define the type somewhere else for a shorthand. Something like this:
public class MyShorthand : List<List<KeyValuePair<string, string>>> { }
Or you can use a using statement to define a type alias like this:
using MyShorthand = System.Collections.Generic.List<System.Collections.Generic.List<System.Collections.Generic.KeyValuePair<string, string>>>;
If you are accessing the values by the key, use dictionary, that is what is meant for. To reduce the overhead of the dictionaries, try and give them an initial capacity.
Alternatively (if both lists are rather small), you could implement a custom hashing object, something like this (except prettier):
public class MyDictionary
{
private Dictionary<string, string> values;
public MyDictionary()
{
values = new Dictionary<string, string>();
}
public void Add(int index, string key, string value)
{
int hash = ((0xFFFF) & index) * (0xFFFF) + (0xFFFF) & key.GetHashCode();
values.Add(hash, value);
}
public string Get(int index, string key)
{
int hash = ((0xFFFF) & index) * (0xFFFF) + (0xFFFF) & key.GetHashCode();
return values[hash];
}
}
For clarity I would wrap your KeyValuePair<string, string> into something shorter, e.g. StringPair and also define a shorthand for a list of StringPair. This will shorten your syntax and help readability IMHO.
public class StringPair : KeyValuePair<string, string> { }
public class StringPairList : List<stringPair> { }
..
var jaggedList = new List<StringPairList>();

Method chaining generic list extensions

I have a List of a "complex" type - an object with a few string properties. The List itself is a property of another object and contains objects of a variety of types, as shown in this abbreviated class structure:
Customer {
public List<Characteristic> Characteristics;
.
.
.
}
Characteristic {
public string CharacteristicType;
public string CharacteristicValue;
}
I'd like to be able to collect a List of the values of a given type of Characteristics for the current Customer, which I can do in a 2-step process as follows:
List<Characteristic> interestCharacteristics = customer.Characteristics.FindAll(
delegate (Characteristic interest) {
return interest.CharacteristicType == "Interest";
}
);
List<string> interests = interestCharacteristics.ConvertAll<string>(
delegate (Characteristic interest) {
return interest.CharacteristicValue;
}
);
That works fine, but it seems like a long way around. I'm sure I must be missing a simpler way of getting to this list, either by chaining together the FindAll() and Convert() methods, or something else I'm overlooking entirely.
For background, I'm working in .Net 2.0, so I'm limited to the .Net 2 generics, and the Characteristic class is an external dependency - I can't change it's structure to simplify it, and there are other aspects of the class that are important, just not in relations to this problem.
Any pointers or additional reading welcomed.
Here's a generator implementation
public static IEnumerable<string> GetInterests(Customer customer)
{
foreach (Characteristic c in customer.Characteristics)
{
if (c.CharacteristicType == "Interest")
yield return c.CharacteristicValue;
}
}
sadly 3.5 extension methods and lambda are out based on your requirements but for reference here's how to do it:
customer.Characteristics
.Where(c => c.CharacteristicType == "Interest")
.Select(c => c. CharacteristicValue);
I would do some of the work manualy. By doing a FindAll first, and then a Convert, you're looping through your collection twice. It doesn't seem neccessary. If all you want at the end of the day, is a List of CharacteristicValue then just loop through your original collection, and add the CharacteristicValue to a List of each one that matches your criteria. Something like this:
Predicate<Characteristic> criteria = delegate (Characteristic interest)
{
return interest.CharacteristicType == "Interest";
};
List<string> myList = new List<string>();
foreach(Characteristic c in customer.Characteristics)
{
if(criteria(c))
{
myList.Add(c.CharacteristicValue);
}
}
Why not create a Dictionary<string, List<string>>, that way you can add "Interest" as the key, and a list of values as the value. For example:
Customer {
public Dictionary<string, List<string>> Characteristics;
.
.
.
}
...
Characteristics.Add("Interest", new List<string>());
Characteristics["Interest"].Add("Post questions on StackOverflow");
Characteristics["Interest"].Add("Answer questions on StackOverflow");
..
List<Characteristic> interestCharacteristics = Characteristics["Interest"];
Furthermore, if you wanted, you could limit your characteristics to a list of possible values by making it an enum, then use that as the data type of your dictionary's key:
public enum CharacteristicType
{
Interest,
Job,
ThingsYouHate
//...etc
}
then declare your dictionary as:
public Dictionary<CharacteristicType, List<string>> Characteristics;
..
Characteristics.Add(CharacteristicType.Interest, new List<string>());
Characteristics[CharacteristicType.Interest].Add("Post questions on StackOverflow");
Characteristics[CharacteristicType.Interest].Add("Answer questions on StackOverflow");

Categories

Resources