Related
I have 4 dictionary, each contain a button's name and the button's value.
I Have a List that contain the name of each dictionary
private Dictionary<string, int> TableArray = new Dictionary<string, int>() { { "ButtonRMT35", 35 }, { "ButtonRMT17", 17 }, { "ButtonRMT11", 11 }, { "ButtonRMT8", 8 }, { "ButtonRMT5", 5 } };
private Dictionary<string, int> ParArray = new Dictionary<string, int>() { { "ButtonRMP20", 20 }, { "ButtonRMP15", 15 }, { "ButtonRMP10", 10 }, { "ButtonRMP5", 5 } };
private Dictionary<string, int> MaxChipsRPArray = new Dictionary<string, int>() { { "ButtonRPC20", 20 }, { "ButtonRPC15", 15 }, { "ButtonRPC10", 10 }, { "ButtonRPC5", 5 } };
private Dictionary<string, int> QuestionSerieRPArray = new Dictionary<string, int>() { { "ButtonRPQ20", 20 }, { "ButtonRPQ15", 15 }, { "ButtonRPQ10", 10 }, { "ButtonRPQ5", 5 } };
public List<string> DictionaryList = new List<string>() { "TableArray", "ParArray", "MaxChipsRPArray", "QuestionSerieRPArray" };
I would like to do something like that
foreach (var dictionnary in DictionaryList)
{
foreach (var buttonName in dictionnary.Keys)
{
DoSomething();
}
}
Is there a way to do that?
The List<string> (DictionaryList) contains strings. Those strings are not variable identifiers (variable identifiers are not the same as C#/.NET strings; variable identifiers are lexical tokens in the C# language, being parsed by the C# compiler during the build of your program), and thus cannot be used to refer to some variable.[1]
Rather than maintaining strings in your DictionaryList, let it maintain the dictionaries itself:
private Dictionary<string, int> TableArray = ...
private Dictionary<string, int> ParArray = ...
private Dictionary<string, int> MaxChipsRPArray = ...
private Dictionary<string, int> QuestionSerieRPArray = ...
public List<Dictionary<string, int>> DictionaryList = new List<Dictionary<string, int>>()
{
TableArray, ParArray, MaxChipsRPArray, QuestionSerieRPArray
};
If you need to access the dictionaries by some name provided as a string (regardless whether that name would correlate with the variable/field names) you can turn the list into a dictionary of dictionaries (mapping some name to each of your dictionaries) instead:
private Dictionary<string, int> TableArray = ...
private Dictionary<string, int> ParArray = ...
private Dictionary<string, int> MaxChipsRPArray = ...
private Dictionary<string, int> QuestionSerieRPArray = ...
public Dictionary<string, <Dictionary<string, int>>> Dictionaries =
new Dictionary<string, <Dictionary<string, int>>>()
{
["TableArray"] = TableArray,
["MaxChipsRPArray"] = MaxChipsRPArray,
["QuestionSerieRPArray"] = QuestionSerieRPArray
};
...
foreach (var dictionary in Dictionaries.Values)
{
foreach (var buttonName in dictionary.Keys)
{
DoSomething();
}
}
You could then access an individual dictionary by name through the public Dictionaries field like this, for example:
var someDictionaryIWant = Dictionaries["MaxChipsRPArray"];
foreach (var buttonName in someDictionaryIWant.Keys)
{
DoSomething();
}
[1] I just told a grey lie here. For fields and properties, it would be possible to access fields/properties by their field/property name given as a string through a mechanism called "reflection". But reflection is cumbersome (likely even complicated for inexperienced programmers), slow, does not play well with trimming or compiling into native code, is normally not applicable to local variables declared inside methods, etc... But i think it's doubtful that you are looking for some dirty hack-ish way to solve your problem when there are cleaner and more straightforward solutions to your problem.
You are on a right track, however it would be hard to achieve by using variable names.
Use nested list, like this: List<Dictionary<string, int>> dictionaryList
Then add your dictionaries to the list, and iterate over them in the for each loop like you initially wanted to.
I got stuck to change the following array to a dictionary.
public static string[][,] patterns = new string[][,]
{
new string[,] {
{ "1,2,3" },
{ "3,2,5" },
},
new string[,] {
{ "4,4,3" },
{ "7,1,2" },
},
};
This is what I have:
public Dictionary<string, string[]> patterns = new Dictionary<string, string[]>();
I can't fill the array with predefined values.
I want to change to a dictionary, because it has a key.
Can I also change the above array to a key and values format?
I want something like this: { "keyNameExample1", "1,2,3", "4,5,6", "etc"}. I want do something like this: patterns["keyNameExample", 1 (integer array pack)]; or patterns["keyNameExample", 2]; (to get the second arrays)
{ "keyNameExample1", "1,2,3", "4,5,6", "etc"} { "keyNameExample2", "5,7,8", "1,1,1", "etc"} and get it like this: patterns["keyNameExample1", 2]; or patterns["keyNameExample2", 1];
can make it even shorter like:
public static Dictionary<string, string[]> demo = new Dictionary<string, string[]>
{
{ "abc", new[]{"1","2"}},
{ "def", new[]{"3","4"}},
};
and with C# 9 you can even do:
public static Dictionary<string, string[]> demo = new()
{
{ "abc", new[]{"1","2"}},
{ "def", new[]{"3","4"}},
};
You can just make it a dictionary with a list, and I guess that covers your requirements (index access, variable number of integers for the index element). Here is an example (for the value list I am not sure, whether you really want a string or ints, in case just change the type):
// define dictionary
IDictionary<string, IList<int>> dict = new Dictionary<string, IList<int>>();
// assign values
dict["abc"] = new List<int> { 2, 4, 8 };
dict["def"] = new List<int> { 10, 12, 14 };
// get value
int dictDef2 = dict["def"][1];
Finally, I got it.
public static Dictionary<string, string[]> demo = new Dictionary<string, string[]>
{
{ "abc",
new string[]
{
"1",
"2"
}
},
{ "def",
new string[]
{
"3",
"4"
}
},
};
Contains check:
if (demo.ContainsKey("abc"))
{
}
Get the value(s):
demo["abc"][0]
Thanks for any help.
If you want to change existing array, you can try Linq:
using System.Linq;
...
public static string[][,] patterns = new string[][,] {...}
...
public Dictionary<string, string[]> patternsDict = patterns
.Select((value, index) => (
key : $"keyNameExample{index}",
value : value.OfType<string>().ToArray()))
.ToDictionary(pair => pair.key, pair => pair.value);
Note, that we have to convert (flatten) 2d array into ordinal one
If you want just to declare dictionary and fill it:
public Dictionary<string, string[]> patterns = new Dictionary<string, string[]>() {
{"keyExample1", new string[] { "1,2,3", "3,2,5" }},
{"keyExample1", new string[] { "4,4,3", "7,1,2" }},
};
public string[][,] patterns = new string[][,] { new string[,] { { "1,2,3" }, { "3,2,5" } }, new string[,] { { "4,4,3" }, { "7,1,2" } } };
Dictionary<string, string[,]> patternsDictionary = new Dictionary<string, string[,]>();
for (int i = 0; i < patterns.Length; i++)
{
patternsDictionary.Add(i.ToString(), patterns[i]);
}
Console.WriteLine(patternsDictionary["0"][0,1]); // Returns 2 - from { "1,2,3" }
I want to assign some static values to my KeyValuePair object.
private IEnumerable<KeyValuePair<string, string>> getCountries()
{
return new List<KeyValuePair<string, string>>()
{
{ "code1", "value1" },
{ "code2", "value2" }
};
}
But this is throwing nooverloaded method error.
return new List<KeyValuePair<string, string>>()
{
new KeyValuePair<string, string>("code1", "value1"),
new KeyValuePair<string, string>("code2", "value2"),
};
If you're using .NET Core 2.0+, you can use the slightly less verbose:
return new List<KeyValuePair<string, string>>()
{
KeyValuePair.Create("code1", "value1"),
KeyValuePair.Create("code2", "value2"),
};
In C# 9, you can use target-typed new to write this as:
return new List<KeyValuePair<string, string>>()
{
new("code1", "value1"),
new("code2", "value2"),
};
Or with Dictionary you can achieve desired initialization style
var pairs = new Dictionary<string, string>
{
{ "one", "first" },
{ "two", "second" },
}.ToList();
pairs.Should().BeOfType<List<KeyValuePair<string, string>>>(); // Pass
Notice, that if later in the code you are going to just enumerate list of key value pairs, then you can use dictionary without explicitly converting it to the list.
var pairs = new Dictionary<string, string>
{
{ "one", "first" },
{ "two", "second" },
}
// later somewhere in the code
foreach(var pair in pairs)
{
Console.WriteLine($"{pair.Key}: {pair.Value}")
}
If you are using values internally (inside class), you can use tuples.
private IEnumerable<(string Code, string Name)> GetCountries()
{
yield return ("code", "Earth");
yield return ("code", "Vulkan");
}
Which later can be consumed in more readable way
foreach(var country in GetCountries())
{
Console.WriteLine($"{country.Code}: {country.Name}")
}
If type used across application, then instead of using key-value pairs you can show intentions of your code to the readers of your code and create custom type.
public class Country
{
public string Code { get; }
public string Name { get; }
public Country(string code, string name)
{
Code = code;
Name = name;
}
}
private IEnumerable<Country> GetCountries()
{
yield return new Country("code", "Earth");
yield return new Country("code", "Vulkan");
}
Which later can be consumed in more readable way
foreach(var country in GetCountries())
{
Console.WriteLine($"{country.Code}: {country.Name}")
}
You need to consider that both Key and Value properties of the generic class are read-only, so you cannot set them directly. Instead you need to take advantage of the class's constructor in order to set the desired pairs.
public IEnumerable<KeyValuePair<string, string>> getCountries()
{
var keyValue1 = new KeyValuePair<string,string>("code1","value1");
var keyvalue2 = new KeyValuePair<string,string>("code2","value2");
var keyValueList = new List<KeyValuePair<string, string>> {keyValue1, keyvalue2};
return keyValueList;
}
As i know, the method to add values for dictionary as below.
Dictionary<string, string> myDict = new Dictionary<string, string>();
myDict.Add("a", "1");
If I declared "myDictDict" as the style below.
IDictionary<string, Dictionary<string, string>> myDictDict = new Dictionary<string, Dictionary<string, string>>();
myDictDict .Add("hello", "tom","cat"); ?// How to add value here.
thank you.
The proper way is like this:
// myDictDict is Dictionary<string, Dictionary<string, string>>
Dictionary<string, string> myDict;
string key = "hello";
if (!myDictDict.TryGetValue(key, out myDict)) {
myDict = new Dictionary<string, string>();
myDictDict.Add(key, myDict);
}
myDict.Add("tom", "cat");
This will extract the dictionary corresponding to the key (hello in your example) or create it if necessary and then will add the key/value pair to that dictionary. You could even extract this into an extension method.
static class Extensions {
public static void AddToNestedDictionary<TKey, TNestedDictionary, TNestedKey, TNestedValue>(
this IDictionary<TKey, TNestedDictionary> dictionary,
TKey key,
TNestedKey nestedKey,
TNestedValue nestedValue
) where TNestedDictionary : IDictionary<TNestedKey, TNestedValue> {
dictionary.AddToNestedDictionary(
key,
nestedKey,
nestedValue,
() => (TNestedDictionary)(IDictionary<TNestedKey, TNestedValue>)
new Dictionary<TNestedKey, TNestedValue>());
}
public static void AddToNestedDictionary<TKey, TNestedDictionary, TNestedKey, TNestedValue>(
this IDictionary<TKey, TNestedDictionary> dictionary,
TKey key,
TNestedKey nestedKey,
TNestedValue nestedValue,
Func<TNestedDictionary> provider
) where TNestedDictionary : IDictionary<TNestedKey, TNestedValue> {
TNestedDictionary nested;
if (!dictionary.TryGetValue(key, out nested)) {
nested = provider();
dictionary.Add(key, nested);
}
nested.Add(nestedKey, nestedValue);
}
}
I left out guarding against null input to keep the idea clear.
Usage:
myDictDict.AddToNestedDictionary(
"hello",
"tom",
"cat",
() => new Dictionary<string, string>()
);
or
myDictDict.AddToNesteDictionary("hello", "tom", "cat");
IDictionary<string,Dictionary<string,string>> myDictDict = new Dictionary<string,Dictionary<string,string>>();
Dictionary<string,string> dict = new Dictionary<string, string>();
dict.Add ("tom", "cat");
myDictDict.Add ("hello", dict);
You can use C# 3's collection initializers, like this:
IDictionary<string, Dictionary<string, string>> myDictDict = new Dictionary<string, Dictionary<string, string>> {
{ "hello", new Dictionary<string, string> { "Tom", "Cat" } }
};
If the dictionary already exists, you can write
dict.Add("hello", new Dictionary<string, string> { "Tom", "Cat" });
Note that this will only work if hello isn't an existing key in the outer dictionary. If it might be, you should use Jason's answer.
To handle this the "simple" way : something like this :
myDictDict.Add("some string", new Dictionary<string, string>());
myDictDict["some string"].Add("another", "string");
To respond directly to the OP's test case : (note the edit added below reflects a desire to correct the syntax of SLaks's answer : code tested and validated against Framework 3.5 Client profile in VS 2010 Beta 2)
// a simple case of creating an instance of a dictionary
// of type <string, string>
// and using .NET 3.0's (FrameWork => 3.5) collection initializer syntax
Dictionary<string, string> twoStringDict = new Dictionary<string, string>()
{
{"key one", "value one"},
{"key two", "value two"}, // note : an "extra" comma does not cause an error here
};
// more complex case as in the question on StackOverFlow
// where dictionary is type <string, Dictionary<string, string>>
// and using .NET 3.0's (FrameWork => 3.5) collection initializer syntax
Dictionary<string, Dictionary<string, string>> myDictDict = new Dictionary<string, Dictionary<string, string>>()
{
{ "key one",
new Dictionary<string, string>() { { "innerKeyOne", "innerValueOne" }}},
{ "key two",
new Dictionary<string, string>() { { "innerKeyTwo", "innerValueTwo" }}}
};
// syntax for adding another key value pair to the complex case
myDictDict.Add("key three", new Dictionary<string, string>() { { "innerKeyThree", "innerValueThree" }});
IDictionary<string, Dictionary<string, string>> myDictDict = new Dictionary<string, Dictionary<string, string>>();
var subDict = new Dictionary<string, string>();
myDictDict .Add("hello", subDict );
subDict.Add("tom", "cat");
You can define an extension method like this :
static void Add(this IDictionary<string, Dictionary<string, string>> dict, string a, string b, string c){
dict.Add(a, new Dictionary<string,string>(){{b,c}};
}
and then use it as :
myDictDict.Add("hello", "tom","cat");
I'm looking for a way to have a function such as:
myFunction({"Key", value}, {"Key2", value});
I'm sure there's something with anonymous types that would be pretty easy, but I'm not seeing it.
The only solution I can think of is to have a params KeyValuePair<String, object>[] pairs parameter, but that ends up being something similar to:
myFunction(new KeyValuePair<String, object>("Key", value),
new KeyValuePair<String, object>("Key2", value));
Which is, admittedly, much uglier.
EDIT:
To clarify, I'm writing a Message class to pass between 2 different systems. It contains a ushort specifying the the Message Type, and a dictionary of string to object for "Data" associated with the message. I'd like to be able to pass all this information in the constructor, so I am able to do this:
Agent.SendMessage(new Message(MessageTypes.SomethingHappened, "A", x, "B", y, "C", z));
or similar syntax.
When the syntax is bad for an otherwise decent pattern, change the syntax. How about:
public void MyFunction(params KeyValuePair<string, object>[] pairs)
{
// ...
}
public static class Pairing
{
public static KeyValuePair<string, object> Of(string key, object value)
{
return new KeyValuePair<string, object>(key, value);
}
}
Usage:
MyFunction(Pairing.Of("Key1", 5), Pairing.Of("Key2", someObject));
Even more interesting would be to add an extension method to string to make it pairable:
public static KeyValuePair<string, object> PairedWith(this string key, object value)
{
return new KeyValuePair<string, object>(key, value);
}
Usage:
MyFunction("Key1".PairedWith(5), "Key2".PairedWith(someObject));
Edit: You can also use the dictionary syntax without the generic brackets by deriving from Dictionary<,>:
public void MyFunction(MessageArgs args)
{
// ...
}
public class MessageArgs : Dictionary<string, object>
{}
Usage:
MyFunction(new MessageArgs { { "Key1", 5 }, { "Key2", someObject } });
Since C# 7.0, you can use value tuples. C# 7.0 not only introduces a new type but a simplified syntax for tuple types and for tuple values. A tuple type is simply written as a list of types surrounded by braces:
(string, int, double)
The corresponding elements are named Item1, Item2, Item2. You can also specify optional aliases. These aliases are only syntactic sugar (a trick of the C# compiler); the tuples are still based on the invariant (but generic) System.ValueTuple<T1, T2, ...> struct.
(string name, int count, double magnitude)
Tuple values have a similar syntax, except that you specify expressions instead of types
("test", 7, x + 5.91)
or with the aliases
(name: "test", count: 7, magnitude: x + 5.91)
Example with params array:
public static void MyFunction(params (string Key, object Value)[] pairs)
{
foreach (var pair in pairs) {
Console.WriteLine($"{pair.Key} = {pair.Value}");
}
}
It is also possible to deconstruct a tuple like this
var (key, value) = pair;
Console.WriteLine($"{key} = {value}");
This extracts the items of the tuple in two separate variables key and value.
Now, you can call MyFunction with a varying number of arguments easily:
MyFunction(("a", 1), ("b", 2), ("c", 3));
It allows us to do things like
DrawLine((0, 0), (10, 0), (10, 10), (0, 10), (0, 0));
See: New Features in C# 7.0
Funny, I just created (minutes ago) a method that allows to do that, using anonymous types and reflection :
MyMethod(new { Key1 = "value1", Key2 = "value2" });
public void MyMethod(object keyValuePairs)
{
var dic = DictionaryFromAnonymousObject(keyValuePairs);
// Do something with the dictionary
}
public static IDictionary<string, string> DictionaryFromAnonymousObject(object o)
{
IDictionary<string, string> dic = new Dictionary<string, string>();
var properties = o.GetType().GetProperties();
foreach (PropertyInfo prop in properties)
{
dic.Add(prop.Name, prop.GetValue(o, null) as string);
}
return dic;
}
A bit of a hack, but you could have your Message class implement the IEnumerable interface and give it an Add method. You'll then be able to use collection initializer syntax:
Agent.SendMessage
(
new Message(MessageTypes.SomethingHappened) {{ "foo", 42 }, { "bar", 123 }}
);
// ...
public class Message : IEnumerable
{
private Dictionary<string, object> _map = new Dictionary<string, object>();
public Message(MessageTypes mt)
{
// ...
}
public void Add(string key, object value)
{
_map.Add(key, value);
}
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable)_map).GetEnumerator();
// or throw a NotImplementedException if you prefer
}
}
Using a dictionary:
myFunction(new Dictionary<string, object>(){
{"Key", value},
{"Key2", value}});
Which is straight forward, you need only one new Dictionary<K, V>, not for each argument. It's trivial to get the keys and values.
Or with an anonymous type:
myFunction(new {
Key = value,
Key2 = value});
Which is not very nice to use inside the function, you'll need reflection. This would look something like this:
foreach (PropertyInfo property in arg.GetType().GetProperties())
{
key = property.Name;
value = property.GetValue(arg, null);
}
(Staight from my head, probably some errors...)
Use a Dictionary ...
void Main()
{
var dic = new Dictionary<string, object>();
dic.Add( "Key1", 1 );
dic.Add( "Key2", 2 );
MyFunction( dic ).Dump();
}
public static object MyFunction( IDictionary dic )
{
return dic["Key1"];
}
Here's more of the same:
static void Main(string[] args)
{
// http://msdn.microsoft.com/en-us/library/bb531208.aspx
MyMethod(new Dictionary<string,string>()
{
{"key1","value1"},
{"key2","value2"}
});
}
static void MyMethod(Dictionary<string, string> dictionary)
{
foreach (string key in dictionary.Keys)
{
Console.WriteLine("{0} - {1}", key, dictionary[key]);
}
}
Some details on initialising a dictionary can be found here.
With dynamic type in C# 4.0:
public class MyClass
{
// Could use another generic type if preferred
private readonly Dictionary<string, dynamic> _dictionary = new Dictionary<string, dynamic>();
public void MyFunction(params dynamic[] kvps)
{
foreach (dynamic kvp in kvps)
_dictionary.Add(kvp.Key, kvp.Value);
}
}
Call using:
MyFunction(new {Key = "Key1", Value = "Value1"}, new {Key = "Key2", Value = "Value2"});
You can do that:
TestNamedMethod(DateField => DateTime.Now, IdField => 3);
where DateField and IdField are supposed to be a 'string' identifiers.
The TestNameMethod:
public static string TestNameMethod(params Func<object, object>[] args)
{
var name = (args[0].Method.GetParameters()[0]).Name;
var val = args[0].Invoke(null);
var name2 = (args[1].Method.GetParameters()[0]).Name;
var val2 = args[1].Invoke(null);
Console.WriteLine("{0} : {1}, {2} : {3}", name, val, name2, val2);
}
Performance is 5% faster than using Dictionary. Disadvantage: you can't use variable as a key.
You could also reference the nugetpackage "valuetuple", which allows you to do the following:
public static void MyFunction(params ValueTuple<string, object>[] pairs)
{
var pair = pairs[1];
var stringValue = pair.item1;
var objectValue = pair.item2;
}
You can then call the method like this:
MyFunction(("string",object),("string", object));
You could use Tuples to achieve something similar to #Bryan Watts's Pairing.Of without the extra class:
public static void MyFunction(params Tuple<string, int>[] pairs)
{
}
MyFunction(Tuple.Create("foo", 1), Tuple.Create("bar", 2));
So I'm new and can't currently add comments, but this is just a suggestion to improve #Bryan Watts's idea of the Pairing.of class by making it generic, allowing it to be easily used by other classes.
public class Pairing
{
public static KeyValuePair<TKey, TValue> of<TKey, TValue>(TKey key, TValue value)
{
return new KeyValuePair<TKey, TValue>(key, value);
}
}