Given a String that is a Key contained in Dictionary<String, List<String>>, how do I retrieve the KeyValuePair<String, List<String>> that corresponds to that Key?
The problem with other answers using FirstOrDefault is that it will sequentially search the entire dictionary until it finds a match, and you lose the benefit of having a hashed lookup. It seems more sensible if you really need a KeyValuePair to just build one, like this:
public class Program
{
public static void Main(string[] args)
{
var dictionary = new Dictionary<string, List<string>>
{
["key1"] = new List<string> { "1" },
["key2"] = new List<string> { "2" },
["key3"] = new List<string> { "3" },
};
var key = "key2";
var keyValuePair = new KeyValuePair<string, List<string>>(key, dictionary[key]);
Console.WriteLine(keyValuePair.Value[0]);
}
}
(with credit to David Pine for the original code in his answer).
Here's a fiddle for that: https://dotnetfiddle.net/Zg8x7s
Usually you want the value associated with the key, for example:
Dictionary<String, List<String>> dictionary = GetDictionary();
var value = dictionary["key"];
But you can use Linq to get the entire KeyValuePair:
var dictionary = new Dictionary<string, List<string>>
{
["key1"] = new List<string> { "1" },
["key2"] = new List<string> { "2" },
["key3"] = new List<string> { "3" },
};
var keyValuePair = dictionary.FirstOrDefault(kvp => kvp.Key == "key2");
Console.WriteLine(keyValuePair?.Value[0]); // Prints "2"
Here is a .NET Fiddle.
Related
I have an <int, string> dictionary and I am trying to check an IEnumerable of objects to see, whether a particular attribute is contained in the dictionary. I am aware of Contains but I can't seem to reverse it if it makes sense.
If it were just one value I'd be fine but I need the list to go through the whole dictionary for each item in the list.
Currently I am using this:
foreach (var item in model)
{
if (dictionary.Values.Contains(object.Attribute))
{
list.Add(object);
}
}
Thank you!
Take a look at the code below, and if you want to play with it use this Fiddle. This takes Jon Skeet's advice to use a HashSet.
// your dictionary of items
var dict = new Dictionary<int, string>();
dict.Add(0, "Zero");
dict.Add(2, "Two");
dict.Add(4, "Four");
// as suggested by Jon Skeet, create a HashSet to be more performant
var hs = new HashSet<string>(dict.Values);
// list of unfiltered items
var list = new List<dynamic>()
{
new { Id = 0, Name = "Zeroth", PropertyYouWantToCheck = "Zero" },
new { Id = 1, Name = "First", PropertyYouWantToCheck = "One" },
new { Id = 2, Name = "Second", PropertyYouWantToCheck = "Two" },
new { Id = 3, Name = "Third", PropertyYouWantToCheck = "Three" },
new { Id = 4, Name = "Fourth", PropertyYouWantToCheck = "Four" },
};
// LINQ query to filter the list
var filteredList = list.Where(i => hs.Contains(i.PropertyYouWantToCheck));
// output the name of the filtered items
Console.WriteLine(string.Join(", ", filteredList.Select(fl => fl.Name)));
I am currently facing an issue where I want to add different values to the same Key in a foreach loop.
List<KeyValuePair<string, Dictionary<string, string>>> sysList = new List<KeyValuePair<string, Dictionary<string, string>>>();
Dictionary<string, string> newSystem = new Dictionary<string, string>();
string line1="";
string line2="";
string quit="";
foreach(Worksheet ws in workbook.Worksheets)
{
while(quit != q)
{
newSystem.Clear();
line1 = Console.ReadLine();
line2 = Console.ReadLine();
quit = Console.ReadLine();
}
newSystem.Add(line1, line2);
sysList.Add(new KeyValuePair<string, Dictionary<string, string>>(ws.Name,newSystem));
}
For the first iteration (within while) of the first Worksheet ws everything is fine. If the I choose to do >1 iterations within this Worksheet, there is a new entry added, but the Dictionary values are all the same, f.e.:
syList[0]: "worksheetName","test1","test2"
syList[1]: "worksheetName","test1","test2"
syList[2]: "worksheetName","test1","test2"
If there are several foreach iterations, the names stay the same, but the Dictionary Key and Values added by newSys are the same [AFTER the second foreach iteration]:
syList[0]: "worksheetName1","test1","test2"
syList[1]: "worksheetName1","test1","test2"
syList[2]: "worksheetName1","test1","test2"
syList[3]: "worksheetName2","test1","test2"
syList[4]: "worksheetName2","test1","test2"
Initially I tried using Dictionaries, but could not handle the same keys properly and did not find a proper solution except for using List.
I am very grateful for any help provided.
If there are additional details that you require, please, let me know.
Edit:
desired result (example):
#########: ws.Name, line1, line2
syList[0]: "worksheetName1","ABC","1"
syList[1]: "worksheetName1","DEF","2"
syList[2]: "worksheetName1","ABC","5"
syList[3]: "worksheetName2","ABD","4"
syList[4]: "worksheetName2","ZZZ","1"
In case you don't want to maintain any uniqueness in the keys and just want a flat list, you can use the C#7 tuple syntax to build your list.
List<string> sheetNames = new List<string>() { "worksheetName1", "worksheetName2" };
var sysList = new List<(string SheetName, string line1, string line2)>();
string line1 = string.Empty;
string line2 = string.Empty;
string quit = string.Empty;
foreach (var sheet in sheetNames)
{
while (quit != "E")
{
line1 = Console.ReadLine();
line2 = Console.ReadLine();
quit = Console.ReadLine();
sysList.Add((sheet, line1, line2));
}
quit = string.Empty;
}
Try code below :
List<List<string>> syList = new List<List<string>>() {
new List<string>() {"worksheetName1","test1","test2"},
new List<string>() {"worksheetName1","test1","test2"},
new List<string>() {"worksheetName1","test1","test2"},
new List<string>() {"worksheetName2","test1","test2"},
new List<string>() {"worksheetName2","test1","test2"}
};
Dictionary<string, Dictionary<string, List<string>>> dict = syList
.GroupBy(x => x.First(), y => y)
.ToDictionary(x => x.Key, y => y
.GroupBy(a => a.Skip(1).FirstOrDefault(), b => b.Last())
.ToDictionary(a => a.Key, b => b.ToList()));
//using normal looping
Dictionary<string, Dictionary<string, List<string>>> dict2 = new Dictionary<string, Dictionary<string, List<string>>>();
foreach (List<string> sy in syList)
{
if (dict2.ContainsKey(sy[0]))
{
Dictionary<string, List<string>> tempDict = dict2[sy[0]];
if (tempDict.ContainsKey(sy[1]))
{
tempDict[sy[1]].Add(sy[2]);
}
else
{
List<string> newList = new List<string>() { sy[2] };
tempDict.Add(sy[1], newList);
}
}
else
{
Dictionary<string, List<string>> newDict = new Dictionary<string, List<string>>();
newDict.Add(sy[1], new List<string> { sy[2] });
dict2.Add(sy[0], newDict);
}
}
I am new to C# and I am trying to define a Dictionary having:
as key:
a string
as value:
a List of Lists of strings.
What I could came up (not entirely sure it's right?) is this:
var peopleWithManyAddresses = new Dictionary<string, List<List<string>>> {};
Now, if the above is right, I would like to know how to populate one item of peopleWithManyAddresses.
Intellisense is telling me that the following is correct only up until "Lucas":
peopleWithManyAddresses.Add("Lucas", { {"first", "address"}, {"second", "address"} });
What's the correct syntax for it?
P.S. I know I could use a class, but for learning purposes I'd like to do it this way for now.
To initialize the List<List<string>> object, you have to use the new List<List<string>> { ... } syntax. And to initialize each sub list you have to use a similar syntax, i.e. new List<string> {... }. Here is an example:
var peopleWithManyAddresses = new Dictionary<string, List<List<string>>>();
peopleWithManyAddresses.Add("Lucas", new List<List<string>>
{
new List<string> { "first", "address" },
new List<string> { "second", "address" }
});
Your initialization statement is correct.
Using C# 6.0, you can use the following syntax to populate one item:
var dict = new Dictionary<string, List<List<string>>>
{
["Lucas"] = new[]
{
new[] { "first", "address" }.ToList(),
new[] { "second", "address" }.ToList(),
}.ToList()
};
You could use the following to populate two items:
var dict = new Dictionary<string, List<List<string>>>
{
["Lucas"] = new[]
{
new[] { "first", "address" }.ToList(),
new[] { "second", "address" }.ToList(),
}.ToList(),
["Dan"] = new[]
{
new[] { "third", "phone" }.ToList(),
new[] { "fourth", "phene" }.ToList(),
}.ToList(),
};
If you want to add more data later, you can do the following:
dict["Bob"] = new[]
{
new[] { "fifth", "mailing" }.ToList(),
new[] { "sixth", "mailing" }.ToList(),
}.ToList();
first I create List separated from Dictionary:
List<string> someList = new List<string<();
var otherList = new List<List<string>>();
var peopleWithManyAddresses = new Dictionary<string, List<List<string>>> {};
First add strings in someList
someList.Add("first");
someList.Add("addresss");
Then add in otherList:
otherList.Add(someList);
Now create new List of strings:
var thirdList = new List<string>();
thirdList.Add("second");
thirdList.Add("addresss");
And add the last list of strings in other list and add in dictionary
otherList.Add(thirdList);
peopleWithManyAddresses.Add("Lucas", otherList);
I have a unique double corresponding to a variation of three strings. I want to populate a dictionary or something such that I can call something like dict[key1][key2][key3] and get the value.
I've tried a whole bunch of things like
Dictionary<string, Dictionary<string, double>> dict = new Dictionary<string, Dictionary<string, double>> {
{ "Foo", {"Bar", 1.2 } },
{ "Foo", {"Test", 3.4 } }
};
Which gives me syntax errors and errors like "Error 4 A namespace cannot directly contain members such as fields or methods"
And
Dictionary<double, Tuple<string, string>> dict = {
{1.23, "Blah", "Foo"}
};
Which gives me errors like "Error 1 Can only use array initializer expressions to assign to array types. Try using a new expression instead."
And
object dict = new Dictionary<string, Dictionary<string, Dictionary<string, string>>>();
dict["k1"] = new Dictionary<string, Dictionary<string, string>>();
dict["k1"]["k2"] = new Dictionary<string, string>();
dict["k1"]["k2"]["k3"] = 3.5;
Which gives me syntax errors and errors like "Error 2 Invalid token '"k1"' in class, struct, or interface member declaration"
How should I go about this? Thanks in advance.
![enter image description here][1]
Edit: Trying Jonesy's code:
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
string[] grades = { "Grade 1", "Grade 5", "Grade 8", "ASTM A325", "316 Stainless", "Monel", "Brighton Best 1960" };
string[] sizes = { "#1", "2", "3", "4", "5", "6", "8", "10", "12", "1/4", "5/16", "3/8", "7/16", "1/2", "9/16", "5/8", "3/4", "7/8", "1", "1-1/8", "1-1/4", "1-3/8", "1-1/2" };
var dict = new Dictionary<string, Dictionary<string, Dictionary<string, double>>>();
dict["k1"] = new Dictionary<string, Dictionary<string, double>>();
dict["k1"]["k2"] = new Dictionary<string, double>();
dict["k1"]["k2"]["k3"] = 3.5;
public Form1()
{
InitializeComponent();
}
your last attempt is close, you want:
var dict = new Dictionary<string, Dictionary<string, Dictionary<string, double>>>();
dict["k1"] = new Dictionary<string, Dictionary<string, double>>();
dict["k1"]["k2"] = new Dictionary<string, double>();
dict["k1"]["k2"]["k3"] = 3.5;
you want var instead of object
(or Dictionary<string, Dictionary<string, Dictionary<string, double>>> if you like scrolling)
and your very last string should be a double.
As I understood, you have data and want to perform lookup in it. Why can't you just use some database for that purpose?
But if you really want to hardcode all values, you can. Just don't initialize dictionary manually, make simplifications - parse data in runtime.
Something like this. (I suppose, that you are novice in c# programming, so I've created new Console Application and copy-pasted all the code for your convenience)
public class Program
{
// harcode all data as string
const string RawData =
"k11,k12,k13=3.4;" +
"k21,k22,k23=4.42;" +
"k31,k32,k33=5.91;" +
"k41,k42,k43=8.14;" +
"k51,k52,k53=4.13;" +
"k61,k62,k63=5.4";
static void Main(string[] args)
{
// create dictionary from hardcoded string
var data = ParseData();
// use Tuple as key for data lookup
var value = data[Tuple.Create("k11", "k12", "k13")];
// check, that value equals expected one
Debug.Assert(value == 3.4);
}
private static IDictionary<Tuple<string, string, string>, double> ParseData()
{
var parsedData =
RawData
.Split(';')
.Select(ParseRow)
.ToDictionary(x => x.Item1, x => x.Item2);
return parsedData;
}
private static Tuple<Tuple<string, string, string>, double> ParseRow(string row)
{
var parts = row.Split('=');
var coefficients = ParseCoefficients(parts[0]);
var value = Double.Parse(parts[1], CultureInfo.InvariantCulture);
return Tuple.Create(coefficients, value);
}
private static Tuple<string, string, string> ParseCoefficients(string row)
{
var coeffs = row.Split(',');
var result = Tuple.Create(coeffs[0], coeffs[1], coeffs[2]);
return result;
}
}
As another simplification, you can use custom class as dictionary key instead of nested dictionaries. Write your own(pay attention, that it should override equality members Equals and GetHashCode), or use something from base class library. Tuple<string, string, string> is the perfect one.
I want to store the following values into a dictionary:
key (string) - values (list of strings)
aaa - myfirstvalue1
aaa - myfirstvalue2
bbb - myfirstvalue3
ccc - myfirstvalue4
ccc - myfirstvalue5
Dictionary:
Dictionary<string, List<string> myvalues = new Dictionary<string, List<string>>();
I tried to store these values but I got the duplicate key error.
Dictionaries have the feature that a key can be added only once. You have the right type, but the way you add the data matters.
You can initialize the dictionary with the data provided like this:
Dictionary<string, List<string>> myvalues = Dictionary<string, List<string>>
{
{ "aaa", new List<string> { "myfirstvalue1", "myfirstvalue2" } },
{ "bbb", new List<string> { "myfirstvalue3" } },
{ "ccc", new List<string> { "myfirstvalue4", "myfirstvalue5" } },
};
With this, each key has one list of strings assigned to it. You can add more values like this:
var key = "aaa"; // for example
if (myvalues.ContainsKey(key)
{
myvalues[key].Add("new value");
}
else
{
myvalues.Add(key, new List<string> { "new value" });
}
You can retrieve values like this:
List<string> aaaVals = myvalues["aaa"];
and then convert that List<string> to an Array with List.ToArray().