Store and access 2D data - c#

If I have a data structure defined as:
Dictionary<KeyValuePair<int, int>, object> rangedValue;
and I populate it as such:
rangedValue = new Dictionary<KeyValuePair<int, int>, object>()
{
{ new KeyValuePair<int, int>(0,0), 424681 },
{ new KeyValuePair<int, int>(1,0), 1072301 },
{ new KeyValuePair<int, int>(2,0), 99111 },
{ new KeyValuePair<int, int>(3,0), 467874 },
{ new KeyValuePair<int, int>(0,1), 195066 },
{ new KeyValuePair<int, int>(1,1), 1171412 },
{ new KeyValuePair<int, int>(2,1), 0 },
{ new KeyValuePair<int, int>(3,1), 128504 }
}
and I want to iterate over it in a coordinated fashion, as in by (x, y) coordinate value and retrieve the value at that point, the best I can come up with is this:
foreach (var relativeXOffset in rangedValue.Keys.Select(kv => kv.Key).Distinct()) // Note distinct here, otherwise returns duplicates
{
foreach (var relativeYOffset in rangedValue.Keys.Select(kv => kv.Value).Distinct())
{
var myObject = rangedValue[new KeyValuePair<int, int>(relativeXOffset, relativeYOffset)];
// Do something with myObject...
}
}
This works for me but it also seems to be a bit rubbish. My requirements are to store an object against a set of coordinates and then be able to iterate over them in a coordinated fashion. Can anyone help with a nice solution, either on the storage or retrieval side (or, ideally, both)?

Create a specialized class with two coordinates and the data at this point:
public class XYD
{
int x;
int y;
object data;
}
Store these classes in a List:
List<XDY> xydList = new List<XYD();
xydList.Add(new XYD { x=0, y=0, data=424681 });
...
This creates a good storage and allows to iterate over your data. But search and retrieval times are O(n).
If you need faster acces you should create an additional dictionary:
Dictionary<Tuple<int,int>,XYZ> lookup;
which allows for a fast search of data given the coordinates.

Related

How to loop through multiple dictionaries to obtain KVP?

I currently have 20 Dictionary<string, Vector3> that are storing TimeStamp Key and Vector3 Value.
E.g.
Dictionary<string, Vector3> rWrist = new Dictionary<string, Vector3>();
Dictionary<string, Vector3> rThumbProximal = new Dictionary<string, Vector3>();
Dictionary<string, Vector3> rThumbDistal = new Dictionary<string, Vector3>();
Dictionary<string, Vector3> rThumbTip = new Dictionary<string, Vector3>();
Dictionary<string, Vector3> rIndexKnuckle = new Dictionary<string, Vector3>();
On exit, I am attempting to loop through each dictionary to generate a CSV with TimeStamp and X,Y,Z coordinates.
I was successful in generating a one to two CSVs manually.
E.g.
foreach (KeyValuePair<string, Vector3> kvp in rWrist)
{
writer.WriteLine("{0},{1},{2},{3}", kvp.Key, kvp.Value.x, kvp.Value.y, kvp.Value.z);
}
But... to do this manually for all 20 dictionaries would be a pain. I am pretty lost on how I could iterate through each dictionary at once.
E.g.
for (int i = 0; i < paths.Count; i++)
{
if (!File.Exists(paths[i]))
{
File.WriteAllText(paths[i], null);
}
using (var writer = new StreamWriter(paths[i]))
{
writer.WriteLine("{0},{1},{2},{3}", "Time", "xPos", "yPos", "zPos");
foreach (KeyValuePair<string, Vector3> kvp in LOOP-THROUGH-MULTIPLE-DICTIONARIES-HERE)
{
writer.WriteLine("{0},{1},{2},{3}", kvp.Key, kvp.Value.x, kvp.Value.y, kvp.Value.z);
}
}
}
I'm not a software developer by trade so any help would be greatly appreciated!
Edit for Clarity:
I am using HoloLens2 to poll positional data every tick
Using the internal clock - each tick is stored as a Key and the value is assigned the Vector3 position of that joint at that tick
Each dictionary may or may not have the same TimeStamps if HoloLens2 doesn't detect a finger pose that tick.
I need to export different .CSV for each joint for Data Analysis
I need to export different .CSV for each joint for Data Analysis
From my understanding, that requirement contradicts your previous statement:
I am pretty lost on how I could iterate through each dictionary at once.
, but if you need to export the joint data to separate .CSV files, I would suggest something similar to the following:
var vectorDataByJointName = new Dictionary<string, Dictionary<string, Vector3>>
{
[nameof(rWrist)] = rWrist,
[nameof(rThumbProximal)] = rThumbProximal,
[nameof(rThumbDistal)] = rThumbDistal,
[nameof(rThumbTip)] = rThumbTip,
[nameof(rIndexKnuckle)] = rIndexKnuckle,
// and so on for the remaining joints
};
foreach (var jointVectorData in vectorDataByJointName)
{
// File creation here (using jointVectorData.Key as file name?)
writer.WriteLine("{0},{1},{2},{3}", "Time", "xPos", "yPos", "zPos");
foreach (var kvp in jointVectorData.Value)
{
writer.WriteLine("{0},{1},{2},{3}", kvp.Key, kvp.Value.x, kvp.Value.y, kvp.Value.z);
}
}
(nameof(rWrist) will simply produce the string "rWrist", and may be replaced by strings directly if that's preferred (e.g. ["Right wrist"] = rWrist rather than [nameof(rWrist)] = rWrist).)
Is it possible instead of thinking about looping through all dictionaries at the same time you actually need to keep a master list of all your keys, and loop through all possible dictionary keys? Which in your instance are timestamps? This will then allow you to operate on each dictionary at the same time. Here is an example I did in LinqPad. The Dump() is similar to WriteLine().
var timestampKeys = new [] {"timestamp1","timestamp2","timestamp3"};
Dictionary<string, string> rWrist = new Dictionary<string, string>();
Dictionary<string, string> rThumbProximal = new Dictionary<string, string>();
rWrist.Add("timestamp1","vectorWrist1");
rWrist.Add("timestamp3","vectorWrist2");
rThumbProximal.Add("timestamp1","vectorThumb1");
rThumbProximal.Add("timestamp2","vectorThumb2");
rThumbProximal.Add("timestamp3","vectorThumb3");
foreach(var timestampKey in timestampKeys)
{
if(rWrist.ContainsKey(timestampKey))
rWrist[timestampKey].Dump();
if(rThumbProximal.ContainsKey(timestampKey))
rThumbProximal[timestampKey].Dump();
}
// outputs:
//vectorWrist1
//vectorThumb1
//vectorThumb2
//vectorWrist2
//vectorThumb3
You could create an IEnumerable<Dictionary<string, Vector3>> (many ways to go about doing that) then use SelectMany to flatten the key-value pairs into a single dimension:
var dictionaries = new[]
{
rWrist,
rThumbProximal,
...
}
foreach( var kvp in dictionaries.SelectMany(d => d) )
{
...
}
Alternatively, just chain Enumberable.Concat calls together
var kvPairs = rWrist.Concat( rThumbProximal )
.Concat( rThumbDistal )
... etc ...;
using System;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
// key = body part
// value = that body part's dictionary
Dictionary<string, Dictionary<string, string>> bigDic = new Dictionary<string, Dictionary<string, string>>();
// <string, string> instead of <string, Vector3>, for demonstration. You can use Vector3 as value without worries.
bigDic.Add("smallDic", new Dictionary<string, string>());
bigDic["smallDic"].Add("12345", "Old Position");
// write
foreach (Dictionary<string, string> sd in bigDic.Values)
{
sd.Add("12346", "New Position");
}
// read
foreach (Dictionary<string, string> sd in bigDic.Values)
{
foreach (string timestamp in sd.Keys)
{
Console.WriteLine(timestamp + ": " + sd[timestamp]);
}
}
}
}
This way, you can access the dictionary through string as keys (Maybe each body part's name, in this case), or simply iterate through them to do same process on each one.
With the case you're mentioning, my guess is you probably won't change the values when iterating through the dictionaries. However if you need to do so, change a dictionary's value while iterating through it is not viable. You can check here for workarounds.

How can I populate this complex List?

I have a complex List data structure which i want to populate but i just cant seem to find a way to seed values to it.
List<Dictionary<List<int>, int>> l1 = new List<Dictionary<List<int>, int>>();
I want something like this,
l1.add( (1,2,3), 6);
I want to add a list of numbers and its sum.
Really not sure why you're doing that but if you really have to
var list = new List<Dictionary<List<int>, int>>();
list.Add(new Dictionary<List<int>, int> {{ new List<int> { 1, 2, 3 }, 6}});
I doubt you really need a list of dictionary of list. Still, you can write some kind of extension method:
public static ListHelpers
{
public void AddSum(this List<Dictionary<List<int>, int>> list, params int[] values)
{
list.Add(new Dictionary<List<int>, int> { values.ToList(), values.Sum() });
}
}
Then use it with:
l1.AddSum(1, 2, 3);

Find matching KVP from Dictionary<List<enum>,string> where search key is List<enum> and return reverse partial matches

I have a Dictionary where the key is a list of enum values, and the value is a simple string.
What I need to do is using another list of enum values find the match KVP.
The curveball and reason for posting here is I also need it to return KVP if the list from my test or search list contains all the items (or enum objects) in any key in the dictionary.
example excerpt of code:
public enum fruit{ apple , orange , banana , grapes };
public class MyClass
{
public Dictionary<List<fruit>, string> FruitBaskets = new Dictionary<List<fruit>, string>;
FruitBaskets.Add(new List<fruit>{apple,orange},"Basket 1");
List<fruit> SearchList = new List<fruit>{orange,apple,grapes};
}
I need to search the dictionary for SearchList and return "Basket 1".
Note that the matching may be backwards than what you would expect for such an example as I need the key to match agains the search list and not vice versa, so extra items in the search list that are not in the key are ok.
I know I could simply iterate the dict and check one by one but I also need this to be as fast as possible as it resides in a loop that is running fairly fast.
What I am currently using is;
public Dictionary<List<fruit>, string> SearchResults;
foreach (KeyValuePair<List<fruit>, string> FruitBasket in FruitBaskets)
{
if (FruitBasket.Key.Except(SearchList).Count() == 0)
SearchResults.Add(FruitBasket);
}
Wondering if there is a better/faster way.
You need to rethink about you choice of Keys in dictionary. There are some major problem with List keys, such as:
You can't use O(1) key lookup with List
Your keys aren't immutable
You can have identical lists as keys without receiving errors, for example you can have:
var a = new[] { fruit.organge }.ToList();
var b = new[] { fruit.organge }.ToList();
fruitBasket.Add(a, "1");
fruitBasket.Add(b, "2");
But is this dictionary valid? I guess not but it depends on your requirements.
You can change Dictionary keys!
For this reasons, you need to change your dictionary key type. You can use combined Enum values instead of using a List with bitwise operators. For this to work, you need to assign powers of 2 to each enum value:
[Flags]
public Enum Fruit
{
Orange = 1,
Apple = 2,
Banana = 4,
Grape = 8
}
You have to combine these enum values to get the desired multi-value enum dictionary key effect:
For [Fruit.Orange, Fruit.Apple] you use Fruit.Orange | Fruit.Apple.
Here's a sample code for combining and decomposing values:
private static fruit GetKey(IEnumerable<fruit> fruits)
{
return fruits.Aggregate((x, y) => x |= y);
}
private static IEnumerable<fruit> GetFruits(fruit combo)
{
return Enum.GetValues(typeof(fruit)).Cast<int>().Where(x => ((int)combo & x) > 0).Cast<fruit>();
}
Now you need a function to get all combinaions (power set) of the SearchList:
private static IEnumerable<fruit> GetCombinations(IEnumerable<fruit> fruits)
{
return Enumerable.Range(0, 1 << fruits.Count())
.Select(mask => fruits.Where((x, i) => (mask & (1 << i)) > 0))
.Where(x=>x.Any())
.Select(x=> GetKey(x));
}
Using these combinations, you can lookup values from dictionary using O(1) time.
var fruitBaskets = new Dictionary<fruit, string>();
fruitBaskets.Add(GetKey(new List<fruit> { fruit.apple, fruit.orange }), "Basket 1");
List<fruit> SearchList = new List<fruit> { fruit.orange, fruit.apple, fruit.grapes };
foreach (var f in GetCombinations(SearchList))
{
if (fruitBaskets.ContainsKey(f))
Console.WriteLine(fruitBaskets[f]);
}
Consider storing your data in a different way:
var FruitBaskets = Dictionary<fruit, List<string>>();
Each entry contains elements that match at least one fruit. Conversion from your structure is as follows:
foreach (var kvp in WobblesFruitBaskets)
{
foreach (var f in kvp.Key)
{
List<string> value;
if (!FruitBaskets.TryGetValue(f, out value))
{
value = new List<string>();
FruitBaskets.Add(f, value);
}
value.Add(kvp.Value);
}
}
Now, the search would look like this: For a composed key searchList you first calculate results for single keys:
var partialResults = new Dictionary<fruit, List<string>>();
foreach (var key in searchList)
{
List<string> r;
if (FruitBaskets.TryGetValue(key, out r))
{
partialResults.Add(key, r);
}
}
Now, what is left is to compose all possible search results. This is the hardest part, which I believe is inherent to your approach: for a key with n elements you have 2n - 1 possible subkeys. You can use one of subset generating approaches from answers to this question and generate your final result:
var finalResults = new Dictionary<List<fruit>, List<string>>();
foreach (var subkey in GetAllSubsetsOf(searchList))
{
if (!subkey.Any())
{
continue; //I assume you don't want results for an empty key (hence "-1" above)
}
var conjunction = new HashSet<string>(partialResults[subkey.First()]);
foreach (var e in subkey.Skip(1))
{
conjunction.IntersectWith(partialResults[e]);
}
finalResults.Add(subkey, conjunction.ToList());
}
I've changed string to List<string> in result's value part. If there is some invariant in your approach that guarantees there will be always only one result, then it should be easy to fix that.
if you create a Dictionary from a Reference Type, you stored just the Reference (Not value), then you can't use simply FruitBaskets[XXX] (except you use the same key that you create the node of dictionary), you must iterate whole of Keys in your dictionary.
I think this function is easy and good for you:
bool Contain(List<fruit> KEY)
{
foreach (var item in FruitBaskets.Keys)
{
if (Enumerable.SequenceEqual<fruit>(KEY,item))
return true;
}
return false;
}
and this,
bool B = Contain(new List<fruit> { fruit.apple, fruit.orange }); //this is True
But if you want to consider the permutation of members, you can use this function:
bool Contain(List<fruit> KEY)
{
foreach (var item in FruitBaskets.Keys)
{
HashSet<fruit> Hkey= new HashSet<fruit>(KEY);
if (Hkey.SetEquals(item))
return true;
}
return false;
}
and here's the output:
bool B1 = Contain(new List<fruit> { fruit.orange, fruit.grapes }); // = False
bool B2 = Contain(new List<fruit> { fruit.orange, fruit.apple }); // = True
bool B3 = Contain(new List<fruit> { fruit.apple, fruit.orange }); // = True

Value lookup using key or vice versa

First of all, apologies for the nasty title. I will correct it later.
I have some data like below,
"BOULEVARD","BOUL","BOULV", "BLVD"
I need a data structure that is O(1) for looking up any of this words by other. For example, if I use a dictionary I would need to store this keys/values like this, which looks odd to me,
abbr.Add("BLVD", new List<string> { "BOULEVARD","BOUL","BOULV", "BLVD" });
abbr.Add("BOUL", new List<string> { "BOULEVARD", "BOUL", "BOULV", "BLVD" });
abbr.Add("BOULV", new List<string> { "BOULEVARD", "BOUL", "BOULV", "BLVD" });
abbr.Add("BOULEVARD", new List<string> { "BOULEVARD", "BOUL", "BOULV", "BLVD" });
Which data structure to use to keep this data appropriate to my querying terms?
Thanks in advance
Create two HashMap - one maps word to a group number. And the other one maps group number to a list of words. This way you save some memory.
Map<String, Integer> - Word to Group Number
Map<Integer, List<String>> - Group Number to a list of words
You need two O(1) lookups - first to get the group number and then by it - get the list of words.
Assuming abbr is a Dictionary<String, IEnumerable<String>>, you could use the following function:
public static void IndexAbbreviations(IEnumerable<String> abbreviations) {
for (var a in abbreviations)
abbr.Add(a, abbreviations);
}
This will populate the dictionary with the provided list of abbreviations such that when any of them is looked up in the dictionary. It is slightly better than the example code you provided, because I am not creating a new object for each value.
From the documentation, "Retrieving a value by using its key is very fast, close to O(1), because the Dictionary(Of TKey, TValue) class is implemented as a hash table."
The choice of dictionary looks fine to me. As mentioned above, you should use the same list to be referenced in the dictionary. The code could go something like this:
var allAbrList = new List<List<string>>
{
new List<string> {"BOULEVARD", "BOUL", "BOULV", "BLVD"},
new List<string> {"STREET", "ST", "STR"},
// ...
};
var allAbrLookup = new Dictionary<string, List<string>>();
foreach (List<string> list in allAbrList)
{
foreach (string abbr in list)
{
allAbrLookup.Add(abbr, list);
}
}
The last part could be converted into LINQ to have less code, but this way it is easier to understand.
If you don't create a new list for each key, then a Dictionary<string, List<string>> will be fast and reasonably memory-efficient as long as the amount of data isn't enormous. You might also be able to get a little extra benefit from reusing the strings themselves, though the optimizer might take care of that for you anyway.
var abbr = new Dictionary<string, List<string>>;
var values = new List<string> { "BOULEVARD","BOUL","BOULV", "BLVD" };
foreach(var aValue in values) abbr.add(value, values);
As Petar Minchev already said, you can split your list into an list of groups and a list of keys that points to this group. To simplify this (in usage) you can write an own implementation of IDictionary and use the Add method to build those groups. I gave it a try and it seems to work. Here are the important parts of the implementation:
public class GroupedDictionary<T> : IDictionary<T,IList<T>>
{
private Dictionary<T, int> _keys;
private Dictionary<int, IList<T>> _valueGroups;
public GroupedDictionary()
{
_keys = new Dictionary<T, int>();
_valueGroups = new Dictionary<int, IList<T>>();
}
public void Add(KeyValuePair<T, IList<T>> item)
{
Add(item.Key, item.Value);
}
public void Add(T key, IList<T> value)
{
// look if some of the values already exist
int existingGroupKey = -1;
foreach (T v in value)
{
if (_keys.Keys.Contains(v))
{
existingGroupKey = _keys[v];
break;
}
}
if (existingGroupKey == -1)
{
// new group
int newGroupKey = _valueGroups.Count;
_valueGroups.Add(newGroupKey, new List<T>(value));
_valueGroups[newGroupKey].Add(key);
foreach (T v in value)
{
_keys.Add(v, newGroupKey);
}
_keys.Add(key, newGroupKey);
}
else
{
// existing group
_valueGroups[existingGroupKey].Add(key);
// add items that are new
foreach (T v in value)
{
if(!_valueGroups[existingGroupKey].Contains(v))
{
_valueGroups[existingGroupKey].Add(v);
}
}
// add new keys
_keys.Add(key, existingGroupKey);
foreach (T v in value)
{
if (!_keys.Keys.Contains(v))
{
_keys.Add(v, existingGroupKey);
}
}
}
}
public IList<T> this[T key]
{
get { return _valueGroups[_keys[key]]; }
set { throw new NotImplementedException(); }
}
}
The usage could look like this:
var groupedDictionary = new GroupedDictionary<string>();
groupedDictionary.Add("BLVD", new List<string> {"BOUL", "BOULV"}); // after that three keys exist and one list of three items
groupedDictionary.Add("BOULEVARD", new List<string> {"BLVD"}); // now there is a fourth key and the key is added to the existing list instance
var items = groupedDictionary["BOULV"]; // will give you the list with four items
Sure it is a lot of work to implement the whole interface but it will give to an encapsulated class that you don't have to worry about, after it is finished.
I don't see a reason to define the value part of your dictionary as a List<string> object, but perhaps that is your requirement. This answer assumes that you just want to know whether the word essentially means "Boulevard".
I would pick one value as the "official" value and map all of the other values to it, like this:
var abbr = new Dictionary<string, string>(StringComparer.CurrentCultureIgnoreCase);
abbr.Add("BLVD", "BLVD"); // this line may be optional
abbr.Add("BOUL", "BLVD");
abbr.Add("BOULV", "BLVD");
abbr.Add("BOULEVARD", "BLVD");
Alternatively, you could define an enum for the value part of the dictionary, as shown below:
enum AddressLine1Suffix
{
Road,
Street,
Avenue,
Boulevard,
}
var abbr = new Dictionary<string, AddressLine1Suffix>(StringComparer.CurrentCultureIgnoreCase);
abbr.Add("BLVD", AddressLine1Suffix.Boulevard);
abbr.Add("BOUL", AddressLine1Suffix.Boulevard);
abbr.Add("BOULV", AddressLine1Suffix.Boulevard);
abbr.Add("BOULEVARD", AddressLine1Suffix.Boulevard);

Is this an efficient code for Multi Key Dictionary in a Method Body?

I just want to ask if:
The code below is efficient?
Is there a better way to handle this?
How to code if additional values for tablename/fieldname pair are needed?
We need to use a multi-key dictionary that contains something like (TableName, FieldName, FieldValue).
I searched some answer but the ones I found so far are not applicable to our setup. We are using 3.5 so no Tuple available yet. We are also integrating this script logic with an application that only allows coding "inside" a method body, so we are limited and cannot create a separate class/structure, etc. Our set up is C#/VS 2010.
Any help is appreciated. Thanks in advance!
Dictionary<string, Dictionary<string, string>> tableList = new Dictionary<string, Dictionary<string, string>>();
Dictionary<string, string> fieldList = new Dictionary<string, string>();
// add fields to field list, then add the field lists to the corresponding table list
// clear field list for next table
// values are just hardcoded here to simplify, but is being read from actual objects in the application
fieldList.Add("Field1", "abc");
fieldList.Add("Field2", "def");
fieldList.Add("Field3", "ghi");
fieldList.Add("Field4", "jkl");
tableList.Add("Table1", new Dictionary<string, string>(fieldList));
fieldList.Clear();
fieldList.Add("Field1", "xyz");
fieldList.Add("Field2", "uvw");
fieldList.Add("Field3", "rst");
tableList.Add("Table2", new Dictionary<string, string>(fieldList));
fieldList.Clear();
fieldList.Add("Field1", "123");
fieldList.Add("Field2", "456");
tableList.Add("Table3", new Dictionary<string, string>(fieldList));
fieldList.Clear();
// Display tables and corresponding fields
foreach (KeyValuePair<string, Dictionary<string, string>> fieldList4 in tableList)
{
foreach (KeyValuePair<string, string> fieldList5 in fieldList4.Value)
{
txtMessage.Text = txtMessage.Text + "\r\nTable=" + fieldList4.Key + ", Field=" + fieldList5.Key + " - " + fieldList5.Value;
}
}
// Try to find tables and fields in the lists, and list the value if found
string tableToFind = "Table2";
string fieldToFind = "Field2";
Dictionary<string, string> tableFields = new Dictionary<string, string>();
if (tableList.Keys.Contains(tableToFind) == true)
{
txtMessage.Text = txtMessage.Text = "\r\nTable=" + tableToFind + " exist in table list";
tableList.TryGetValue(tableToFind, out tableFields);
if (tableFields.Keys.Contains(fieldToFind) == true)
{
foreach(KeyValuePair<string, string> fieldData in tableFields)
{
if (fieldData.Key == fieldToFind)
{
txtMessage.Text = txtMessage.Text + "\r\nTable=" + tableToFind + ", Field=" + fieldData.Key +
" with value=" + fieldData.Value + " exist in table list";
break;
}
}
}
}
You can use the compiler to create a composite key for you: Using anonymous types.
var dictionary = new Dictionary<Object, int>();
dictionary.Add(new{Text="A", Number=1}, 1);
dictionary.Add(new{Text="A", Number=2}, 3);
dictionary.Add(new{Text="B", Number=1}, 4);
dictionary.Add(new{Text="B", Number=2}, 5);
var x = dictionary[new{Text="B", Number=2}];
C# will implement Equals and GetHashcode based on your fields. Thus you do get a key which will behave as you would expect.
There's a whole slew of problems and inefficiencies in your code.
If you're going to create multiple dictionaries, create the dictionaries directly. Don't use a separate instance to fill the values and copy from.
Never use string concatenation in a loop like that. Use a StringBuilder or other similar mechanism to build up your strings. You already have your values in a collection so using String.Join() in conjunction with LINQ would clean that up.
Your approach to get values from the dictionary is awkward to say the least. Normally you'd use TryGetValue() alone to attempt to read the key. Your code uses it incorrectly. If you are going to check if the key exists in the dictionary (using Contains()), then there's no point in using TryGetValue(). To make things worse, you did this then searched for the key manually in the inner dictionary by iterating through the key value pairs.
The typical pattern looks like this:
DictValueType value;
if (myDict.TryGetValue(key, out value))
{
// key was in the dictionary, the value is stored in the `value` variable
}
The code you have could be written much much more efficiently like this:
var tableList = new Dictionary<string, Dictionary<string, string>>
{
{ "Table1", new Dictionary<string, string>
{
{ "Field1", "abc" },
{ "Field2", "def" },
{ "Field3", "ghi" },
{ "Field4", "jkl" },
}
},
{ "Table2", new Dictionary<string, string>
{
{ "Field1", "xyz" },
{ "Field2", "uvw" },
{ "Field3", "rst" },
}
},
{ "Table3", new Dictionary<string, string>
{
{ "Field1", "123" },
{ "Field2", "456" },
}
},
};
// Display tables and corresponding fields
txtMessage.Text = String.Join("\r\n",
tableList.SelectMany(table =>
table.Value.Select(fieldList =>
String.Format("Table={0}, Field={1} - {2}",
table.Key, fieldList.Key, fieldList.Value)
)
).ToArray()
);
// (I hope you have this in a separate method)
// Try to find tables and fields in the lists, and list the value if found
string tableToFind = "Table2";
string fieldToFind = "Field2";
var builder = new StringBuilder(txtMessage.Text); // mostly useful if you have a
// lot of different strings to add
Dictionary<string, string> foundTable;
if (tableList.TryGetValue(tableToFind, out foundTable))
{
builder.AppendLine()
.Append("Table=" + tableToFind + " exist in table list");
string foundField;
if (foundTable.TryGetValue(fieldToFind, out foundField))
{
builder.AppendLine()
.AppendFormat("Table={0}, Field={1} with value={2} exist in table list",
tableToFind, fieldToFind, foundField);
}
}
txtMessage.Text = builder.ToString();
Nested dictionaries aren't a bad thing, it's a nice way to organize hierarchies of keys and values. But to keep it maintainable, you generally should encapsulate everything within another class providing methods to manipulate the data without having to manage the dictionaries directly. You can make it both efficient and maintainable. How to implement this is an exercise left to you.
I don't think so many dictionaries would be 'efficient'.
I think the best way would be to add values into the same dictionary multiple times - assuming you want to be able to index them according to one of the indicies (not all):
dictionary.Add("FField1", "xxx");
dictionary.Add("TTable1", "xxx");
Otherwise use a joining character (like '\0') if you want to index them according to all the indicies together.
dictionary.Add("Table1\0Field1", "xxx");

Categories