So i need to create a data-structure with one Key, sub Key and Value. And a method to Add Key, sub Key and Value.
The Key are unique and can have multiple Sub Keys.
The Sub Key are uniques in the context inside Key and can have multiple Values.
The Values are unique inside the context of the Sub Key.
The first data-structure that comes to my mind was Dictionary (perform time is important for the task).
Then i created the following dictionary.
public class NewCollection : IHoplonCollection
{
class SubIndexAndValue
{
public int subIndex;
public List<string> Value = new List<string>();
}
class DataStructure : IComparable<DataStructure>
{
public string Key;
public List<SubIndexAndValue> subIndexValue = new List<SubIndexAndValue>();
public int CompareTo(DataStructure other)
{
if (Key.CompareTo(other.Key) > 0)
{
return 1;
}else if (Key.CompareTo(other.Key) < 0)
{
return -1;
}else
{
return 0;
}
}
}
SortedDictionary<DataStructure, SubIndexAndValue> colList = new SortedDictionary<DataStructure, SubIndexAndValue>();
public bool Add(string Key, int subIndex, string Value)
{
return true;
}
So as you can see the Add method will receive the Key, Sub Key and Value.
In the future i will need to do a CRUD and sort data.
My question is, how do i handle this? How can i use method like Contains() to check if one Value (string) was already inserted in the dictionary using this data-structure? Or maybe there is an easyer way to do this.
Thanks.
I think that a combination of built-in structures can solve your proposed datastructure:
Dictionary<string,Dictionary<int,HashSet<string>>>
The first dictionary holds list of key-value pairs of string (Key), and for every one of them, the value it's another Dictionary whose key is a unique string (SubKey) and the value is a HashSet<string>, a list of unique strings.
Related
I wrote the code below to get all the values from a dictionary which has the given key.
Dictionary<string,string> _dictionary;
public List<string> GetValuesUsingKey(string key)
{
List<string> outp = new List<string>();
foreach(var d in _dictionary)
{
if (d.Key == key)
{
outp.Add(d.Value);
}
}
return outp;
}
is there a simpler way to achieve this result using LINQ?
Update :
it turned out that i was mislearned about Dictionaries, i though i could use multiple values for a single key but i was wrong
A key in a Dictionary is guaranteed to be unique, so there's no need to return a List.
public string GetValueUsingKey(string key)
{
bool isKeyPresent = _dictionary.TryGetValue(key, out var output);
return isKeyPresent ? output : _YOUR_DEFAULT_BEHAVIOUR_;
}
The big advantage of a Dictionary is that the time complexity for insertion and retrieval of values using the key is O(1); if you cycle through all the KeyValuePair it contains you completely nullify the purpose of using a Dictionary as it would make the retrieval O(n)!
Dictionary is a one to one map, you cannot have multiple values for a given key.
ILookup on the other hand supports this scenario, as well as null keys:
using System.Linq;
class Element
{
public string Key { get; }
public string Value { get; }
...
}
IEnumerable<Element> elements = ...
ILookup<string, string> lookup = elements.ToLookup(e => e.Key, e => e.Value);
and then to get your result:
List<string> outp = lookup[key].ToList();
I started learning about MVC 6 and I found this tutorial.
The following code is quoted from the linked site:
//TodoItem.cs
namespace TodoApi.Models
{
public class TodoItem
{
public string Key { get; set; }
public string Name { get; set; }
public bool IsComplete { get; set; }
}
}
The TodoItem class will be a value field in a ConcurrentDictionary:
static ConcurrentDictionary<string, TodoItem> _todos =
new ConcurrentDictionary<string, TodoItem>();
The key field which has string type will contain the same value as TodoItem.Key:
public void Add(TodoItem item)
{
item.Key = Guid.NewGuid().ToString();
_todos[item.Key] = item;
}
Does this means that each time a new item is added the the Key will stored twice(once is the key field of the dictionary and once inside the value field) or I am missing something?
I came across this situation in C++ using std::map too and I always used something like this to avoid storing the value of Key two times:
struct Item
{
//std::string Key;
std::string Name;
bool IsComplete;
};
std::map<std::string, Item> items;
// ^^ Item.Key
Does this means that each time a new item is added the the Key will
stored twice(once is the key field of the dictionary and once inside
the value field) or I am missing something?
In .NET System.String type is a reference type, so you shouldn't be worried about the key being stored twice. It will be a single instance in memory to which both the Key of the dictionary and the Key property of the item are simply pointing to. So don't worry about redundancy in this situation. The ConcurrentDictionary structure that you are using here is just a simple wrapper of pointers around your actual data.
Also worth mentioning another interesting property of the System.String type in .NET. Even if you have 2 different instances of a string with the same value the runtime could decide to intern them and they will point to the same data in memory:
string a = "abc";
string b = "abc";
bool res = object.ReferenceEquals(a, b); // true
first off - yes, I had a look at this question: Is object creation in getters bad practice?.
I am also not talking about initializing an object in the accessors / mutators, it is about a specific part of the object I want to be returned in a specific way.
My question is more specific; It does not necessarily only apply to C#, however I am currently looking for a solution to implement in my C# project.
I have a class with a dictionary that maps date objects to a decimal value. In one accessor, I want to return a list of all the keys of the dictionary, another accessors returns the values.
What I also want to have is an accessor that gives me the decimal values in a specific format. It would look something like this:
class Class
{
// Some other properties...
// ....
private Dictionary<DateTime, decimal> dict;
public Class(Dictionary<DateTime, decimal> dict)
{
this.dict = dict;
}
private string FormatTheWayIWant(decimal dt)
{
// Format decimal value.
string s = String.Format("{0:F}", dt);
return s;
}
public ReadOnlyCollection<DateTime> DateTimes
{
get { return new ReadOnlyCollection<DateTime>(this.dict.Keys.ToList()); }
}
public ReadOnlyCollection<decimal> Values
{
get { return new ReadOnlyCollection<decimal>(this.dict.Values.ToList()); }
}
public ReadOnlyCollection<string> FormattedStrings
{
get
{
// Format each decimal value they way I want.
List<string> list = new List<string>();
foreach (decimal dt in dict.Keys)
{
list.Add(FormatTheWayIWant(dt));
}
return new ReadOnlyCollection<string>(list);
}
}
}
This way I can make the following calls (which is my goal!):
DateTime dateTime = DateTimes[0];
decimal s = Values[0];
string formattedS = FormattedStrings[0];
The problem with this approach is that I create a new list everytime I invoke the FormattedStrings accessor, even if I only need one of the formatted strings. I know this is not good practice and can introduce unnecessary performance issues...
The alternatives I thought of are:
I could extend the decimal class and implement a custom ToString()-method.
Or overwrite the KeyValuePair<DateTime, decimal> class and use an indexer in my class.
Or I create a method with a parameter for the index and return just the one formatted string.
Or I could have an own list for the accessor, which gets updated in the set-method for my dictionary everytime I update the dictionary.
The question I have is, is there a way to make this work with an accessor instead of a method, creating custom classes or having strange side effects on other objects when assigning a value?
Thank you in advance.
Ofcourse this can be done with an accessor. You just have to create 3 separate classes for each desired element of your processed collection. Those classes should have their own indexers, so you would be able to access the elements as a list. The difference would be, that they compute each element on demand (wchich is called lazy initialization). So it would go like this (example for your FormattedStrings):
class Class
{
// ...
MyFormattedStrings FormattedStrings
{
get {return new MyFormattedStringsIndexer<string>(this.dict.Values.ToList());}
}
}
class MyFormattedStringsIndexer<T>
{
private IList<T> list; // we take only reference, so there is no overhead
public MyFormattedStringsCollection (IList<T> list)
{
this.list = list;
}
// the indexer:
public T this[int i]
{
get
{
// this is where the lazy stuff happens:
// compute the desired element end return it
}
set
{
// ...
}
}
}
Now you can use your Class like this:
string formattedS = FormattedStrings[5];
and each element you access will be computed as you access it. This solution also has the advantage of separating concerns, so should you ever had to implement different logic for one of your 3 accessors it would be just a matter of extending one of the indexers.
You can read more about indexeres here: http://msdn.microsoft.com/en-us/library/6x16t2tx.aspx
This is VB, but you get the idea...
Public Class Something
Public Property Items As Dictionary(Of DateTime, String)
Public Readonly Property FormattedItem(ByVal index As Int32) As String
' add error checking/handling as appropriate
Return Me.Items.Keys(index).ToString("custom format") ' or whatever your formatting function looks like.
End Property
End Class
It looks like a good candidate for a new class
public class MyObject
{
public DateTime Key {get;set;}
public String Name {get;set;}
public String FormattedString {get;}
}
And then it can be used in any container (List<MyObject>, Dictionary<MyObject>, etc).
Your Dates and Strings property getters are returning a new list on each call. Therefore if a caller does the following:
Class myClass = ...
for(i=0; i<myClass.Strings.Count; i++)
{
var s = myClass.Strings[i];
...
}
then each iteration of the loop will create a new list.
I'm not clear on what you're really trying to achieve here. You are wrapping the dictionary's Keys and Values properties in ReadOnlyCollections. This gives you an indexer, which doesn't have much meaning as the order of the Keys in a Dictionary<TKey, TValue> is unspecified.
Coming (at last!) to your question, if you want to do the formatting in a "lazy" manner, you could create a custom class that implements a readonly IList<string>, and wraps your list of keys (IList<DateTime>). Most of the implementation is boilerplate, and your indexer will do the formatting. You could also cache the formatted values so that you only format once if accessed multiple times. Something like:
public class MyFormattingCollection : IList<string>
{
private IList<decimal> _values;
private IList<string> _formattedValues;
public MyFormattingCollection(IList<DateTime> values)
{
_values = values;
_formattedValues = new string[_values.Count];
}
public string this[int index]
{
get
{
var result = _formattedValues[index];
if (result == null)
{
result = FormatTheWayIWant(_values[index]);
_formattedValues[index] = result;
}
return result;
}
set
{
// Throw: it's a readonly collection
}
}
// Boilerplate implementation of readonly IList<string> ...
}
Hi all I am having a requirement where I have to assign multiple keys and for that multiple keys I have to assign multiple values
My requirement is as follows. I am having EmpID, PayYr and PayID for each employee.
Assume I get my data as follows:
EmpID 1000 1000 1000 1000
PayYr 2011 2011 2011 2012
PayID 1 2 3 1
I would like to have my dictionary so that the dictionary with key value result is as follows:
1000 - 2011 - 1,2,3
1000 - 2012 - 1
I tried some thing as follows
public struct Tuple<T1, T2>
{
public readonly T1 Item1;
public readonly T2 Item2;
public Tuple(T1 item1, T2 item2)
{
Item1 = item1;
Item2 = item2;
}
}
Sample code
for (int empcnt = 0; empcnt < iEmpID.Length; empcnt++)
{
for (int yrcnt = 0; yrcnt < ipayYear.Length; yrcnt++)
{
List<int> lst1 = new List<int>();
var key1 = new Tuple<int, int>(iEmpID[empcnt], ipayYear[yrcnt]);
if (!dictAddValues.ContainsKey(key1))
{
dictAddValues.Add(key1, lst1);
lst1.Add(lst[yrcnt]);
}
}
}
But I am not getting my result as i required so can any one help me.
Personally, I'd probably use a Dictionary of Dictionaries, e.g. IDictionary<int, IDictionary<int, IList<int>>>. Not I am not entirely sure how you intend to access or facilitate this data; that will have a large impact on how efficient my suggestion is. On the upside, it would allow you to -- relatively easily -- access data, if and only if you access it in the order you set up your dictionaries.
(On second thought, simply the type declaration itself is so ugly and meaningless, you might want to skip what I said above.)
If you are accessing fields rather randomly, maybe a simple denormalized ICollection<Tuple<int, int, int>> (or equivalent) will have to do the trick, with aggregation in other parts of your application as needed. LINQ can help here a lot, especially its aggregation, grouping, and lookup features.
Update: Hopefully this clarifies it:
var outerDictionary = new Dictionary<int, Dictionary<int, List<int>>>();
/* fill initial values
* assuming that you get your data row by row from an ADO.NET data source, EF, or something similar. */
foreach (var row in rows) {
var employeeId = (int) row["EmpID"];
var payYear = (int) row["PayYr"];
var payId = (int) row["PayID"];
Dictionary<int, int> innerDictionary;
if (!outerDictionary.TryGet(employeeId, out innerDictionary)) {
innerDictionary = new Dictionary<int, int>();
outerDictionary.Add(employeeId, innerDictionary);
}
List<int> list;
if (!innerDictionary.TryGet(payYear)) {
list = new List<int>();
innerDictionary.Add(payYear, list);
}
list.Add(payId);
}
/* now use it, e.g.: */
var data = outerDictionary[1000][2011]; // returns a list with { 1, 2, 3 }
Take it with a grain of salt though; see comment.
I think you're missing the Comparer piece. See if the article below helps.
Dictionary with a Custom Key
http://www.codeproject.com/Articles/23610/Dictionary-with-a-Custom-Key
If the key is part of the class then use KeyedCollection.
It is a Dictionary where the key is derived from the object.
Under the covers it is Dictionary. D Don't have to repeat the key in the Key and Value.
Why take a chance the key is not the same in the Key as the Value. Don't have to duplicate the same information in memory.
KeyedCollection Class
Indexer to expose the composite key
using System.Collections.ObjectModel;
namespace IntIntKeyedCollection
{
class Program
{
static void Main(string[] args)
{
UInt16UInt16O Emp1 = new UInt16UInt16O(34, 1990);
Emp1.PayIDs.Add(1);
Emp1.PayIDs.Add(2);
UInt16UInt16O Emp2 = new UInt16UInt16O(34, 1990, new List<byte>{3,4});
if (Emp1 == Emp2) Console.WriteLine("same");
if (Emp1.Equals(Emp2)) Console.WriteLine("Equals");
Console.WriteLine("Emp1.GetHashCode " + Emp1.GetHashCode().ToString());
UInt16UInt16OCollection Employees = new UInt16UInt16OCollection();
Employees.Add(Emp1);
//this would fail
//Employees.Add(Emp2);
Employees.Add(new UInt16UInt16O(35, 1991, new List<byte> { 1 } ));
Employees.Add(new UInt16UInt16O(35, 1992, new List<byte> { 1, 2 } ));
Employees.Add(new UInt16UInt16O(36, 1992));
Console.WriteLine(Employees.Count.ToString());
// reference by ordinal postion (note the is not the long key)
Console.WriteLine(Employees[0].GetHashCode().ToString());
// reference by Int32 Int32
Console.WriteLine(Employees[35, 1991].GetHashCode().ToString());
Console.WriteLine("foreach");
foreach (UInt16UInt16O emp in Employees)
{
Console.WriteLine(string.Format("HashCode {0} EmpID {1} Year {2} NumCodes {3}", emp.GetHashCode(), emp.EmpID, emp.Year, emp.PayIDs.Count.ToString()));
}
Console.WriteLine("sorted");
foreach (UInt16UInt16O emp in Employees.OrderBy(e => e.EmpID).ThenBy(e => e.Year))
{
Console.WriteLine(string.Format("HashCode {0} EmpID {1} Year {2} NumCodes {3}", emp.GetHashCode(), emp.EmpID, emp.Year, emp.PayIDs.Count.ToString()));
}
}
public class UInt16UInt16OCollection : KeyedCollection<UInt16UInt16S, UInt16UInt16O>
{
// This parameterless constructor calls the base class constructor
// that specifies a dictionary threshold of 0, so that the internal
// dictionary is created as soon as an item is added to the
// collection.
//
public UInt16UInt16OCollection() : base(null, 0) { }
// This is the only method that absolutely must be overridden,
// because without it the KeyedCollection cannot extract the
// keys from the items.
//
protected override UInt16UInt16S GetKeyForItem(UInt16UInt16O item)
{
// In this example, the key is the part number.
return item.UInt16UInt16S;
}
// indexer
public UInt16UInt16O this[UInt16 EmpID, UInt16 Year]
{
get { return this[new UInt16UInt16S(EmpID, Year)]; }
}
}
public struct UInt16UInt16S
{ // required as KeyCollection Key must be a single item
// but you don't reaaly need to interact with Int32Int32s
public readonly UInt16 EmpID, Year;
public UInt16UInt16S(UInt16 empID, UInt16 year) { this.EmpID = empID; this.Year = year; }
}
public class UInt16UInt16O : Object
{
// implement you properties
public UInt16UInt16S UInt16UInt16S { get; private set; }
public UInt16 EmpID { get { return UInt16UInt16S.EmpID; } }
public UInt16 Year { get { return UInt16UInt16S.Year; } }
public List<byte> PayIDs { get; set; }
public override bool Equals(Object obj)
{
//Check for null and compare run-time types.
if (obj == null || !(obj is UInt16UInt16O)) return false;
UInt16UInt16O item = (UInt16UInt16O)obj;
return (this.EmpID == item.EmpID && this.Year == item.Year);
}
public override int GetHashCode() { return ((UInt32)EmpID << 16 | Year).GetHashCode() ; }
public UInt16UInt16O(UInt16 EmpID, UInt16 Year)
{
UInt16UInt16S uInt16UInt16S = new UInt16UInt16S(EmpID, Year);
this.UInt16UInt16S = uInt16UInt16S;
PayIDs = new List<byte>();
}
public UInt16UInt16O(UInt16 EmpID, UInt16 Year, List<byte> PayIDs)
{
UInt16UInt16S uInt16UInt16S = new UInt16UInt16S(EmpID, Year);
this.UInt16UInt16S = uInt16UInt16S;
this.PayIDs = PayIDs;
}
}
}
}
You need to implement Equals and GetHashCode in your Tuple struct:
public override bool Equals(object obj)
{
if (!(obj is Tuple<T1, T2>))
return false;
var t = (Tuple<T1, T2>)obj
return (this.Item1 == t.Item1 && this.Item2 == t.Item2);
}
public override int GetHashCode()
{
return (Item1 ^ Item2 );
}
I'm not 100% sure of the exact data you want to use as a key. I think 2? 2 Integer values? That's what I'll assume below, but if you want three or the type is different, just adjust accordingly. I suggest the following (step 1 is necessary, step 2 is optional but I'd do it)
Step 1 Creating your own key struct, to be used as the key in a standard dictionary. Give it 2 properties (or three, whatever) for your values that will act as the key, and/or a Constructor taking/setting those values.
Specify a GetHashCode method. Something like:
public override int GetHashCode()
{
unchecked
{
return (_empId * 397) ^ _payYr;
}
}
Note: Yes, you could use a Tuple. Tuples . . . aren't as cool as the first seem. Your property names will be Item1, etc. Not very clear. And you often end up wanted to overriding and add things soon enough. Just start from scratch.
Like this:
public struct PayKey {
private int _empId
private int _payYr;
public PayKey (int empId, int payYr) {
_empId = empId;
_payYr = payYr;
}
public override int GetHashCode()
{
{
return (_empId * 83) ^ _payYr;
}
}
}
Note: If any of your multiple values that you want to use in your combined key are reference types, you should probably create a class instead of a struct. If so, you'll also need to override Equals for it to work properly as a dictionary key.
public override bool Equals( object pkMaybe ){
if( pkMaybe is PayKey ) {
PayKey pk = (PayKey) pkMaybe ;
return _empId = pk.EmpId && _payYr = pk.PayYr;
}
else {
return false;
}
}
(And add public properties for your key values if you haven't already.)
Or, if you create the custom dictionary as I mention below, it would be convenient use a IEqualityComparer. (Basically, if you use a class as your key, you have to make sure the dictionary will see two identical PayKey object as "equal". By default, even with equal values, they are references to different objects, so the framework will consider them not equal)
Step 2 Create a class that inherits from Dictionary. Give it two additional methods:
An add method that takes your two key parameters as well as the value you want to add. Inside, you'll construct one of your key structs and call its base add method, with the key object as the key and your value of course as the value.
an overload for item or named as you wish. This method will take as parameters the 2 integers of your key, and return the item. Inside this method you'll construct one of your key structs, and call the base item method with the key struct to retrieve the object.
Additionally, for your eventual convenience, you'll probably want to add other overloads to your dictionary, where you can specify your key values, rather than having to construct your own key struct each time. For example, the first thing I'd probably do is add a KeyExists property that took my two key values.
Try taking a look at https://www.nuget.org/packages/Microsoft.Experimental.Collections from microsoft which contains the MultiValueDictionary type.
MultiValueDictionary is a generic dictionary that associates a single
key with one or more values. Values can be added and removed
independently.
This is similar to How to keep the order of elements in hashtable, except for .NET.
Is there any Hashtable or Dictionary in .NET that allows you to access it's .Index property for the entry in the order in which it was added to the collection?
A NameValueCollection can retrieve elements by index (but you cannot ask for the index of a specific key or element). So,
var coll = new NameValueCollection();
coll.Add("Z", "1");
coll.Add("A", "2");
Console.WriteLine("{0} = {1}", coll.GetKey(0), coll[0]); // prints "Z = 1"
However, it behaves oddly (compared to an IDictionary) when you add a key multiple times:
var coll = new NameValueCollection();
coll.Add("Z", "1");
coll.Add("A", "2");
coll.Add("Z", "3");
Console.WriteLine(coll[0]); // prints "1,3"
The behaviour is well documented, however.
Caution: NameValueCollection does not implement IDictionary.
As an aside: Dictionary<K,V> does not have any index you can use, but as long as you only add elements, and never remove any, the order of the elements is the insertion order. Note that this is a detail of Microsoft's current implementation: the documentation explicitly states that the order is random, so this behavior can change in future versions of the .NET Framework or Mono.
If this is something that you need to keep track of efficiently, then you are using the wrong data structure. Instead, you should use a SortedDictionary where the key is tagged with the index of when it was added (or a timestamp) and a custom IComparer that compares two keys based on the index (or the timestamp).
You can use a separate list to store the elements in the order they are added. Something along the lines of the following sample:
public class ListedDictionary<TKey, TValue> : IDictionary<TKey, TValue>
{
List<TValue> _list = new List<TValue>();
Dictionary<TKey, TValue> _dictionary = new Dictionary<TKey,TValue>();
public IEnumerable<TValue> ListedValues
{
get { return _list; }
}
public void Add(TKey key, TValue value)
{
_dictionary.Add(key, value);
_list.Add(value);
}
public bool ContainsKey(TKey key)
{
return _dictionary.ContainsKey(key);
}
public ICollection<TKey> Keys { get { return _dictionary.Keys; } }
public bool Remove(TKey key)
{
_list.Remove(_dictionary[key]);
return _dictionary.Remove(key);
}
// further interface methods...
}
Is there any Hashtable or Dictionary in .NET that allows you to access it's .Index property for the entry in the order in which it was added to the collection?
No. You can enumerate over all the items in a Hastable or Dictionary, but these are not guaranteed to be in any sort of order (most likely they are not)
You would have to either use a different data structure altogether, (such as SortedDictionary or SortedList) or use a separate list to store the order in which they were added. You would want to wrap the ordered list and your dictionary/hashtable in another class to keep them synched.
Take a look at the OrderedDictionary class. Not only can you access it via keys, but also via an index (position).
An alternative is to create an array of stuctures, so instead of using
dictionary.Add{"key1","value1"}
you create a structure with the key/value like:
public struct myStruct{
private string _sKey;
public string sKey{
get { return _sKey; }
set { _sKey = value; }
}
private string _sValue;
public string sValue {
get { return _sValue; }
set { _sValue = value; }
}
}
// create list here
List<myStruct> myList = new List<myStruct>();
// create an instance of the structure to add to the list
myStruct item = new myStruct();
item.sKey = "key1";
item.sValue = "value1";
// then add the structure to the list
myList.Add(item);
Using this method you can add extra dimensions to the list without too much effort, just add a new member in the struct.
Note, if you need to modify items in the list after they have been added you will have to change the struct into a class. See this page for more info on this issue: error changing value of structure in a list