A Pair list with some equals key/values? - c#

I need a Pair list, with "string", "string".
Tried :
Dictionary<string, string> Categories= new Dictionary<string, string>();
but can't add "700", "2" and "700", "3". I need a Pair where I can add everythings, when I want. Like a Vector that can contain N Vector (string, string). Which structure I need? Quickly, because I need to compaire them in LINQ, after :
myStructs = from MyObject s in MyObjects
join c in Categories on s.IDCategory.UniqueID equals c.Key
join d in Categories on s.Stars equals d.Value
select s;

Try List<Tuple<string, string>>, or for increased readability, simply make a new type.
If you need it to make sense during linq, you could transfer the tuple into an anonymous type (using let here) to give the type some sensible property names:
var items = new List<Tuple<string, string>>
{
new Tuple<string, string>("Adam", "1"),
new Tuple<string, string>("Adam", "2")
};
var names = from i in items
let person = new { Name = i.Item1, Number = i.Item2 }
select person.Name;
Makes it a little more readable during a linq query.
It the type is used a lot, I advise creating your own type with better property names for clarity as in Servy's answer. In the long run, Tuple<string, int, bool> is a lot less obvious than:
class Person
{
public string Name { get; set; }
public int Age { get; set; }
public bool LikesCake { get; set; }
}
Tuple equality is based on the equality of all it's properties against an instance of the same type of tuple. For example, new Tuple("Adam", "1").Equals(new Tuple("Adam", "1")) will be true.
Lists also do not stop duplicate items. If you need to enforce uniqueness across all the properties, then HashSet<Tuple<string, string>> is what you need.

Just create your own.
public class Pair
{
public string First {get;set;}
public string Second {get;set;}
}
Then you can have a List<Pair> to hold your data.
There are several possible library classes that you could re-purpose for your own needs, but in particular if this pair actually represents something (meaning you'd rename the class and the properties to something more meaningful) then it can be useful to have it in its own class to denote that. If you did want to just re-use an existing type then Tuple<string,string> would probably be the best choice.

Try using List<KeyValuePair<string, string>>.

A Dictionary is a hashed location keys, so you cannot have duplicates in the dictionary. You could have a list of type <string,string> either by using aKeyValuePair or Tuple

A List<KeyValuePair<string, string>> would probably work well if you're in .NET 3.5 or below, and if 4 or above, List<Tuple<string, string>> would be a winner.

Related

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.

C# make a Dictionary of Lambdas

I'm having a trouble defining a Dictionary for quick accessing Lambda Expressions.
Let's suppose we have a well-known class like this:
class Example
{
public string Thing1;
public DateTime Thing2;
public int Thing3;
}
What a want to do is something like this:
var getters = new Dictionary<string, IDontKnowWhatGoesHere>();
getters.Add("Thing1", x => x.Thing1);
getters.Add("Thing3", x => x.Thing3);
Is this possible?
Edit:
This is my use case for this object:
List<Example> array = new List<Example>();
// We actually get this variable set by the user
string sortField = "Thing2";
array.Sort(getters[sortField]);
Many thanks for your help.
You've got a couple of options. If, as in your example, the things you want to get are all the same type (i.e. String), you can do
var getters = new Dictionary<string, Func<Example, String>>();
However, if they're different types, you'll need to use the lowest common subclass, which in most cases will be Object:
var getters = new Dictionary<string, Func<Example, object>>();
Note that you'll then need to cast the return value into your expected type.
Try:
var getters = new Dictionary<string, Func<Example, object>>();
getters.Add("Thing1", x => x.Thing1);
getters.Add("Thing3", x => x.Thing3);
The first generic type parameter of the Func delegate is the type of the input, and the second generic type parameter is the type of the output (use object because you've different output types).
More about Func: Func<T, TResult> Delegate
var getters = new Dictionary<string, Expression<Func<Example, object>>>();
However, string Thing1 should be public.
I really think you are thinking about this in the wrong way. Why use a dictionary at all? If your class definition is correct, then just use a List<Example>.
List<Example> dataList = new List<Example>();
dataList.Add(new Example { Thing1 = "asdf", Thing2 = "qwert", Thing3 = 2 });
Then you can use linq on it.
IEnumerable<Example> sortedByT3 = dataList.OrderBy(x => x.Thing3);
sortedByT3.Last().Thing2 = "hjkl";
You can also use a dynamic order by provided by Marc Gravell's answer:
var sortedByString = dataList.AsQueryable().OrderBy("Thing2");
No need for lambdas, just direct access to the data.
As everyone has said, you need to make the members public. I would suggest you change it to the following:
public class Example
{
public string Thing1 { get; set; }
public string Thing2 { get; set; }
public int Thing3 { get; set; }
}

Generic Collection which allows same key

Collections like HashTable and Dictionary don't allow to add a value with the same key but I want to store the same values with the same keys in a Collection<int,string>.
Is there a built-in collection which lets me do this?
You can use a List<T> containing a custom class, or even a List<Tuple<int,string>>.
List<Tuple<int,string>> values = new List<Tuple<int,string>>();
values.Add(Tuple.Create(23, "Foo"));
values.Add(Tuple.Create(23, "Bar"));
Alternatively, you can make a Dictionary<int, List<string>> (or some other collection of string), and populate the values in that way.
Dictionary<int, List<string>> dict = new Dictionary<int, List<string>>();
dict.Add(23, new List<string> { "Foo", "Bar" });
This has the advantage of still providing fast lookups by key, while allowing multiple values per key. However, it's a bit trickier to add values later. If using this, I'd encapsulate the adding of values in a method, ie:
void Add(int key, string value)
{
List<string> values;
if (!dict.TryGetValue(key, out values))
{
values = new List<string>();
dict[key] = values;
}
values.Add(value);
}
Use a List with a custom Class.
public class MyClass
{
public int MyInt { get; set; }
public string MyString { get; set; }
}
List<MyClass> myList = new List<MyClass>();
myList.Add(new MyClass { MyInt = 1, MyString = "string" });
In short: The easiest way to go would be a generic List<T> collection while skiping the ArrayList class. Because, there are some performance considerations that you need to take into account.
In addition, you can also use List<KeyValuePair<string,int>>.
This will store a list of KeyValuePair 's that can be duplicate.
In deciding whether to use the List<T> or ArrayList class, both of which have similar functionality, remember that the List<T> class performs better in most cases and is type safe. If a reference type is used for type T of the List<T> class, the behavior of the two classes is identical. However, if a value type is used for type T, you need to consider implementation and boxing issues.
As reference: you may use the following MSDN article - List Class.

Create type and initialize it at run-time

Suppose I have Dictionary like this:
Dictionary<string, string> values = new Dictionary<string, string>()
{
{ "Name" , "John Smith"},
{ "Age", "34"}
};
Now I want to create type from that dictionary and initialize it with values in run-time so that I was able to access it's properties with reflection.
For this example I want object with property Name equals to "Jon Smith" and Age equals to 34.
Edit:
I need this to compare two objects with semantic comparison library such as TestApi. First object created by other code that has strong type
class Person
{
public string Name {get; set;}
public int Age { get; set;}
}
and other I need to create from other source like xml file (but not necessary). Types that would be compared are known only in run-time.
If you're using C# 4 you could use dynamic and ExpandoObject for this - it's not actually creating a new type, but it's close enough in some cases:
IDictionary<string, object> foo = new ExpandoObject();
foreach (var pair in values)
{
foo[pair.Key] = pair.Value;
}
dynamic d = foo;
string name = d.Name;
string age = d.Age; // This will still be a string, not an int
EDIT: I missed that you wanted to access the data with reflection. Using reflection is a way of effectively treating the type like a map - and you've already got it in that form. Why not just access the dictionary directly? The only benefit would be if you wanted to be able to use some types with reflection, and some with a dictionary. In that case I'd create a general-purpose interface with two implementations - one of which got values from a dictionary, and one of which used reflection. That's going to be a lot easier than creating a type on the fly (which is possible, but not a lot of fun).

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

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.

Categories

Resources