Use existing Hashset as Keys to create new dictionary - c#

If i have an existing Hashset of type T, how would i create a dictionary out of it like;
Dictionary<T, object> tmp = new Dictionary<T, object>();
This can be done using the following code
Hashset<string> hashset = new Hashset<string>()
foreach(var key in hashset)
tmp[key] = null;
Is there an easier way of doing this, rather than having a loop?

Yes, by using the overload of the Enumerable.ToDictionary extension method that has both a key selector and a value selector parameter.
var dictionary = hashset.ToDictionary(h => h , h => (object)null);
because you're selecting null for the value, it's necessary to ensure it's a null object (null needs to be specified with a type), hence the cast.

Related

How to instantiate a specific number of items in a dictionary?

I'm trying to declare a Dictionary<Task> with a specific number of items, I tried:
private Dictionary<Task, CancellationToken> bots =
new Dictionary<Task, CancellationToken>(new Task[9], new CancellationToken[9]);
this will return the following error:
you can not convert from 'System.Threading.Tasks.Task []' to 'System.Collections.Generic.IDictionary '
all works if I do this in a List:
private List<Task> bots = new List<Task>(new Task[9]);
As the error shows you're trying something that doesn't exists.
One of the override Dictionary constructor accepts
public Dictionary(IDictionary<TKey, TValue> dictionary);
public Dictionary(IDictionary<TKey, TValue> dictionary, IEqualityComparer<TKey> comparer);
And neither of the parameters you gave is correct.
The 1st input you gave is Task[] and the 2nd is CancellationToken[]
You should create a IDictionary implementation which is usually a Dictionary and then passing it to it.
var example1Original = new Dictionary<Task, CancellationToken>();
example1Original.Add(new Task(DoWork), new CancellationToken());
example1Original.Add(new Task(DoWork), new CancellationToken());
// and more (This procedure can be shorten using a loop)
var example1Result = new Dictionary<Task, CancellationToken>(example1Original);
As you can see, we successfully passed our variable into the Dictionary constructor, this is possible because Dictionary implements IDictionary as we can see here
But the last line is actually redundant, because yes we can pass it, but we don't need to. Because our populated example1Original is already a Dictionary which is what we're aiming to.
So it begs the question, why the Dictionary constructor has it in the first place. Which leads us to our original statement, that IDictionary can have multi implementations which can be passed.
Here are few of IDictionary implementations
(Picture taken from mscorlib.dll using ILSpy)
So your question is actually, how can i populate my Dictionary with a new instances of Task and Cancellation tokens.
This can be done with:
Previous above code. (And shorten more by a loop)
Or using a nice language capability in a shorter manner.
Capabilities we're going to use
System.Linq.Enumerable.Range - Generates a sequence of integral numbers within a specified range.
System.Linq.Enumerable.Select - Projects each element of a sequence into a new form.
The power of Interfaces - For allowing us to use the ToDictionary extension method.
System.Linq.Enumrable.ToDictionary() - Extension method that takes IEnumerable and generates a Dictionary
Enumerable.ToDictionary - Because IDictionary itself implements IEnumerable we can then use the following ToDictionary extension method
Extension method from System.Linq namespace
public static Dictionary<TKey, TElement> ToDictionary<TSource, TKey, TElement>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector);
If we will use those capabilities we can build the following to generate our Dictionary.
var kvpOfTaskCancellation = Enumerable.Range(0, 9) // Generates Enumerable integers sequence.
.Select(i => new KeyValuePair<Task, CancellationToken>(new Task(DoWork), new CancellationToken())) // Iterating and projecting every elements inside the previous generated sequence.
.ToDictionary(kvp => kvp.Key, kvp => kvp.Value); // Mapping each iteration from the previous line KeyValuePair objects to the Dictionary Key and Value.
Which can also be shorten to the following
var kvpOfTaskCancellation2 = Enumerable.Range(0, 9)
.ToDictionary(kvp => new Task(DoWork), kvp => new CancellationToken());
This all works if you want a new Task and Cancellation token.
But if you already have a filled collection of Tasks and CancellationTokens and you want to generate from them a Dictionary, then you can do the following:
var tasks = new Task[3];
// I'm assuming the tasks already been populated
tasks.ToDictionary(kvp => kvp, kvp => new CancellationToken());
But if you also have a CancellationToken array as well, then you can use the following:
var tasks = new Task[3];
var cancellationsTokens = new CancellationToken[9];
// I'm assuming tasks and cancellationToken array already been filled.
Enumerable.Range(0, tasks.Length)
.Select(i => new KeyValuePair<Task, CancellationToken>(tasks[i], cancellationsTokens[i]))
.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
An uninitialized array of Task only contains null elements and you can not have null as the key of a dictionary item, but in general, if you have initialized arrays, you can have dictionaries with those arrays using Linq:
var dictionary = (from token in new CancellationToken[9]
from task in initializedTaskArray
select (task, token)
)
.ToDictionary(x => x.task, x => x.token);
You would need to do something like the following:
private Dictionary<Task, CancellationToken> bots = new Dictionary<Task, CancellationToken>() {
{ new Task(), new CancellationToken() },
{ new Task(), new CancellationToken() },
...
}

Dynamically create a tuple with all the same type and a known number of elements

I am looking to dynamically create tuples of a given size that have all the same type.
So if I wanted a tuple of strings of size three I would get Tuple<string, string, string>
I have tried both to pass strings into the angle brackets for Tuple like this:
string foo = "string, string, string";
Tuple<foo> testTuple = Tuple<foo>(~parameters~);
and to pass an array of types into the angle brackets like this:
List<Type> types = new List<Type>() {"".GetType(), "".GetType(), "".GetType()};
Tuple<types> testTuple = Tuple<foo>(~parameters~);
Neither one of these worked. Does anyone know how to make the described dynamic tuples?
(The reason I want to do this is to use tuples inside of a dictionary like
Dictionary<Tuple<# strings>, int> testDictionary = new Dictionary<Tuple<x # strings>, int>();
Using tuples here is more useful than HashSets because the comparison in tuples is by components instead of by reference so that if I have
Tuple<string, string> testTuple1 = new Tuple<string, string>("yes", "no");
Tuple<string, string> testTuple2 = new Tuple<string, string>("yes", "no");
Dictionary<Tuple<string, string>, string> testDictionary = new Dictionary<Tuple<string, string>, string>() {
{testTuple1, "maybe"}
};
Console.WriteLine(testDict[testTuple2]);
it writes "maybe". If you run this same test with HashSets, it throws an error. If there is a better way to accomplish this same thing, that would also be useful.)
You could do something like this using reflection:
public static object GetTuple<T>(params T[] values)
{
Type genericType = Type.GetType("System.Tuple`" + values.Length);
Type[] typeArgs = values.Select(_ => typeof(T)).ToArray();
Type specificType = genericType.MakeGenericType(typeArgs);
object[] constructorArguments = values.Cast<object>().ToArray();
return Activator.CreateInstance(specificType, constructorArguments);
}
That will give you a tuple for a variable number of elements.
"Does anyone know how to make the described dynamic tuples?"
You can just use Tuple.Create(). For a 3-tuple:
var tupleOfStrings = Tuple.Create("string1", "string2", "string3");
var tupleOfInts = Tuple.Create(1, 2, 3);
Make custom type with List<string> inside (or List<T> if you want generic solution)
Override object.Equals: Use Enumerable.SequenceEqual for inner list in your custom class
Override object.GetHashCode() in order to use your type in dictionary

Read SortedList from Hashtable

How can I read the value from SortedList when I have this structure in Hashtable ?
Below is the example
public SortedList sl = new SortedList();
sl[test] = 1;
Hashtable ht= new Hashtable();
ht.Add("root", sl);
I want to read the sl[test].
You just do the reverse:
SortedList sortedList = (SortedList)ht["root"];
object value = sortedList[test];
As it stands, you will need to cast the result of the hash table back to a SortedList before you can use methods such as the indexer on it, requiring this kind of ugliness:
var result = (ht["root"] as SortedList)[test];
However, if all elements of your hashtable are SortedLists, you can use a generic container such as a Dictionary instead, to avoid the casting:
var dic = new Dictionary<string, SortedList> { { "root", sl } };
result = dic["root"][test];
And you might also consider replacing the SortedList with its generic counterpart, e.g. SortedList<string, int> (depending on the type of 'test'), for the same reasons.

How to get the value out of this type of dictionary in c#

I want to create, because I understand dictionaries are key=>value in C#, a dictionary that is much like key=>value(key=>value)
Currently I I know I can do:
Dictionary<int, int> someVar = new Dictionary<int, int>();
which creates me a key=>value.
To create what I want I could do (this is just a guess, please correct me if I am wrong):
Dictionary<int Dictionray<int, int>> someVar = new Dictionary<int, Dictionray<int, int>>
Now comes the fun part, I want to do ONE and only ONE for loop over this dictponary object YET get all values so it would look something like:
foreach (KeyValuePair<int, int> pair in someVar){
//object = base dictionary key
//object2 = nested dictionary key
//object3 = nested dictionary value
}
Now I come from PHP so this would be dead easy to do in one for loop. what are your ideas? because I am new to C# and the term dictionary (even though php arrays are dictionaries).
I know in C# with a for loop like this I could do: pair.Key and pair.Value.
My second part, is How do I add values to such a dictionary? I know the typical .add(bla, bla) but how do you add values to the nested part?
Iterating
In C#, IDictionary<TKey, TValue> implements IEnumerable<KeyValuePair<TKey, TValue>>. So, you can iterate over an instance of type IDictionary<TKey, TValue> using foreach or a Linq query, and get every KeyValuePair in the data structure. Since your TValue is in this case itself an IDictionary, you can do this on the inner structure as well:
foreach(var kvp in myDictionary)
{
foreach(var innerKvp in kvp.Value)
{
var myValue = innerKvp.Value
//Logic on myValue
}
}
Using the Linq library, you can use SelectMany to get all of the KeyValuePair instances quite elegantly:
myDictionary.SelectMany(kvp => kvp.Value);
SelectMany essentially flattens a list of lists. This Linq query is saying: for each key value pair in my dictionary, get all the inner dictionaries, treat them as lists of key value pairs, and then flatten all those lists. This will return an IEnumerable<KeyValuePair<TKey, TValue>>.
If instead you only care about the values of the inner dictionary, and not the keys, you can use the Values property on IDictionary<TKey, TValue> which returns an IEnumerable<TValue> of all the values in the dictionary. We can then use SelectMany to get a list that contains all the values in the dictionary of dictionaries:
myDictionary.Values.SelectMany(dict => dict.Values);
Read more about IDictionary<TKey, TValue> here and more about KeyValuePair<TKey, TValue> here.
Adding
In order to add an element to this data structure, you'll have to first check if the inner dictionaries are null. Let's say we're trying to add 3 to the dictionary keyed by 2 in the dictionary keyed by 1:
var myInnerDictionary = myDictionary.ContainsKey(1) ? myDictionary[1] : (myDictionary[1] = new Dictionary<int, int>());
myInnerDictionary[1][2] = 3;
Of course this will override a value in that location if it already exists, so you might want to check that as well, or use the Add method, which will not overwrite.
You should also learn about the ToDictionary Linq method which can help you construct dictionaries from other IEnumerables. Read about it here.
use linq to get all the values
var values = someVar.SelectMany(x => x.Values);
as for how to add values to the nested part, you'd just need the key for the outer dictionary for which sub dictionary you want to to add it to:
someVar[key].Add(0, 0);
It's impossible to get all the values including nested by using only one foreach loop, unless nested Dictionaries have a values which you can get without using loop, like this:
foreach (var pair in someVar){
var object1 = (Dictionary<int,int>)pair.Value;
var object2 = object1[0].Value;
var object3 = object1[1].Value;
.....
// To add a values to the nested Dictionary just use Dictionary.Add method:
object1.Add(1,1);
}

Collection Like Dictionary<K, V> That allows Value Change

I understand why there isn't a method built in to do this, however I want a collection object that will allow Value change possibly during Enumeration.
Imagine the following:
Dictionary<string, List<string>> test = new Dictionary<string, List<string>> {{"key", null}};
Lets say I have 20 of these within a class which implements IEnumberable
I'd like to use lambda or a simple foreach to iterate through the class and find the object matching a key, then store my List<T> with the Value parameter.
You might be looking for a collection called multimap. See here for my implementation of it.
As you have discovered you can't change a DictionaryEntry through the Value property - you have to go through the Item accessor using the Key.
One option is to turn your Where results to an array then loop to get the matching Keys:
Dictionary<string, List<string>> test = new Dictionary<string, List<string>>
{{"key", null}};
test.Add("newKey",null);
var matches = test.Where(di => di.Key == "key").ToArray();
foreach(var di in matches) {
test[di.Key] = new List<string> {"one","two"};
You can just use this to modify a value in a dictionary:
public static void ChangeValue(string indexKey,List<string> newValue)
{
if (test.ContainsKey(indexKey))
keysDictionary[indexKey] = newValue;
}
You could avoid using an enumerator altogether, e.g.
var data = myEnumerable.ToArray();
for(var i = 0; i < data.Length; i++) {
// here you can manipulate data[i] to your heart's content
}

Categories

Resources