Populating data to a nested Dictionary Collection - c#

I have a collection
List<Employee> which contain Properties like
Name ,EmployeeID,Address,JobTitle and so on
For every employee there are few column which changes and based upon these few columns i need to update my Active Directory.
So i thot of creating a isEditable field for each column which will signify whether the column has changed or not for a particular employee . But it turns out that i need to create this field for all the columns and the number of columns also changes frequently .
So I came up with nested dictionary collection
Dictionary<int, Dictionary<object, bool>>
which will store the Employee ID as the key and the object type will store all the column names and bool by default will be false
But i don't know how to populate the above nested collection with List<Employee> Collection .
This is what i have tried till now
Dictionary<int, Dictionary<object, bool>> _isEditable = new Dictionary <int, Dictionary<object, bool>>();
foreach (var item in _empColl )
{
foreach (var type in _empColl .GetType ().GetProperties ())
{
_isEditable.Add (item.EmployeeID ,dict.Add (type.Name,false));
}
}
But its throwing error .I'm trying to get the metadata (column names ) from the _empColl for each EmployeeID

You can use LINQ below to get the result:
var _isEditable = _empColl.ToDictionary(item => item.EmployeeID,
item => item.GetType()
.GetProperties()
.ToDictionary(pro => pro.Name,
pro => false));

Related

How to display items in a list with a description of what that list item is in c# console

I am trying to display a list sorted in descending order with each item being displayed with a description of what the value of the item is in VS console app. I’m just not sure how to display the description with each item
Eg. output:
Total monthly expenses//description of list item : $1000//item obtained from list and sorted
Home loan repayment: $700
Vehicle Installment: $300
Thank you
I cannot see where you are getting the description values from. A better way to do this would be to use Dictionary instead of a List.
double cost = textbox1.Text; // cost of item
string des = textbox2.Text; //description of item
//below code goes into a event to add each item cost+description
Dictionary<double, string> io = new Dictionary<double, string>();
io.Add(cost, des);
//below code goes into a event to display all items
foreach(KeyValuePair<double, string> val in io.OrderByDescending(i => i.Key)) {
Console.WriteLine("${0},{1}", val.Key, val.Value);
}
assuming you have fetched the data from the database, store the data in a dictionary collection. The key in the key-value pair of the dictionary set is the product description information, and the value is the specific price. You can first extract the value of the key in the dictionary set for sorting, and then extract the value value in the dictionary set according to the value of the key.
static void main(string[] args)
{
Dictionary<string, int> d = new Dictionary<string, int>();
d.Add("keyboard", 100);
d.Add("mouse", 80);
//get key
var val = d.Keys.ToList();
//sort
val.Sort();
foreach (var key in val)
{
Console.WriteLine(key);
}
}

Need to create a custom object by looping the list in c# is it possible

I need to create a list object based on a list of key-value pair dynamically but I can't assign the key value in object by looping the list.
foreach (KeyValuePair<string, IEnumerable<string>> item in List)
{
string keyValue = item.Key.ToString();
object value = new { item.Key = item.Value };
somefunction(value);
}
the item.key will throw issue. Any suggestions for how to create an object while looping through the list.
For example if the item value is { key: "sampleKey" , value : "sampleValue"} i need to create an object as { "sampleKey" = "sampleValue" }. How can I achive this.
I believe the answer is IEnumerable<string> newList = item.Value; instead of object value = new { item.Key = item.Value };
You could do something with the dynamic keyword and the ExpandoObject (https://learn.microsoft.com/en-us/dotnet/api/system.dynamic.expandoobject?view=net-5.0), but if you're keys are so dynamic, I don't see a point of having them in a class/object at all. Rather store the data as a dictionary, which will then let you retreive data from strings as well.

Is there a way in linq wherin i can insert a row(from dictionary) in datatable using the list of column names c#?

I have a List<Dictionary<string,string>> something like this:
[0] key1 val,key2 val,key3 val
[1] key1 val,key2 val,key3 val
[2] key1 val,key2 val,key3 val
And i have a list of column names in the same order as columns in the datatable.
I want to filter only those keys which are there inside the list from the dictionary and also insert it in the proper order.
I'm able to filter the required keys to be inserted but then how do i insert it in the proper order in linq.
var colList = new List<string>() { "key3", "key1"};
dict.ForEach(p => jsonDataTable.Rows.Add(p.Where(q=>colList.Contains(q.key)).Select(r => r.Value).ToArray()));
I cannot do like this because number of columns will vary and also the method must work when we pass any list of column names:
foreach(var item in dict)
jsonDatatable.Rows.Add(item[colList[0]], item[colList[1]]);
Please suggest some ways.
LINQ will never ever change the input sources. You can only extract data from it.
Divide problems in subproblems
The only way to change the input sources is by using the extracted data to update your sources. Make sure that before you update the source you have materialized your query (= ToList() etc)
You can divide your problem into subproblems:
Convert the table into a sequence of columns in the correct order
convert the sequence of columns into a sequence of column names (still in the correct order)
use the column names and the dictionary to fetch the requested data.
By separating your problem into these steps, you prepare your solution for reusability. If in future you change your table to a DataGridView, or a table in an entity framework database, or a CSV file, or maybe even JSON, you can reuse the latter steps. If in future you need to use the column names for something else, you can still use the earlier steps.
To be able to use the code in a LINQ-like way, my advice would be to create extension method. If you are unfamiliar with extension methods, read Extension Methods Demystified
You will be more familiar with the layout of your table (System.Data.DataTable? Windows.Forms.DataGridView? DataGrid in Windows.Controls?) and your columns, so you'll have to create the first ones yourself. In the example I use MyTable and MyColumn; replace them with your own Table and Column classes.
public static IEnumerable<MyColumn> ToColumns(this MyTable)
{
// TODO: return the columns of the table
}
public static IEnumerable<string> ToColumnNames(this IEnumerable<MyColumn> columns)
{
return columns.Select(column => ...);
}
If the column name is just a property of the column, I wouldn't bother creating the second procedure. However, the nice thing is that it hides where you get the name from. So to be future-changes-proof, maybe create the method anyway.
You said these columns were sorted. If you want to be able to use ThenBy(...) consider returning an IOrderedEnumerable<MyColumn>. If you won't sort the sorted result, I wouldn't bother.
Usage:
MyTable table = ...
IEnumerable<string> columnNames = table.ToColumns().ToColumnNames();
or:
IEnumerable<string> columnNames = table.ToColumns()
.Select(column => column.Name);
The third subproblem is the interesting one.
Join and GroupJoin
In LINQ whenever you have two tables and you want to use a property of the elements in one table to match them with the properties of another table, consider to use (Group-)Join.
If you only want items of the first table that match exactly one item of the other table, use Join: "Get Customer with his Address", "Get Product with its Supplier". "Book with its Author"
On the other hand, if you expect that one item of the first table matches zero or more items from the other table, use GroupJoin: "Schools, each with their Students", "Customers, each with their Orders", "Authors, each with their Books"
Some people still think in database terms. They tend to use some kind of Left Outer Join to fetch "Schools with their Students". The disadvantage of this is that if a School has 2000 Students, then the same data of the School is transferred 2000 times, once for every Student. GroupJoin will transfer the data of the School only once, and the data of every Student only once.
Back to your question
In your problem: every column name is the key of exactly one item in the Dictionary.
What do you want to do with column names without keys? If you want to discard them, use Join. If you still want to use the column names that have nothing in the Dictionary, use GroupJoin.
IEnumerable<string> columNames = ...
var result = columnNames.Join(myDictionary,
columName => columName, // from every columName take the columnName,
dictionaryItem => dictionaryItem.Key, // from every dictionary keyValuePair take the key
// parameter resultSelector: from every columnName and its matching dictionary keyValuePair
// make one new object:
(columnName, keyValuePair) => new
{
// Select the properties that you want:
Name = columnName,
// take the whole dictionary value:
Value = keyValuePair.Value,
// or select only the properties that you plan to use:
Address = new
{
Street = keyValuePair.Street,
City = keyValuePair.City,
PostCode = keyValuePair.Value.PostCode
...
},
});
If you use this more often: consider to create an extension method for this.
Note: the order of the result of a Join is not specified, so you'll have to Sort after the Order
Usage:
Table myTable = ...
var result = myTable.ToColumns()
.Select(column => column.Name)
.Join(...)
.Sort(joinResult => joinResult.Name)
.ToList();
Instead of filtering on the List<Dictionary<string, string>>, filter on the colList so that you will get in the same order and only if the colList is available in the List<Dictionary<string, string>>
This is as per my understanding, please comment if you need the result in any other way.
var dictAllValues = dict.SelectMany(x => x.Select(y => y.Value)).ToList();
// Now you can filter the colList using the above values
var filteredList = colList.Where(x => dictAllValues.Contains(x));
// or you can directly add to final list as below
jsonDataTable.Rows.AddRange(colList.Where(x => dictAllValues.Contains(x)).ToList());

Grouping Items In A List View

I have a Dictionary that is declared thusly:
Dictionary myDictionary<string, List<FCPort>> = new Dictionary<string, List<FCPort>>();
the key is a string representing a switch name. The value is a list of port objects for that switch. I am trying to add the items in the Dictionary to a ListView with this code:
foreach (KeyValuePair<string, List<FCPort>> portpair in results)
{
ListViewItem item1 = new ListViewItem(portpair.Key);
foreach (FCPort port in portpair.Value)
{
item1.SubItems.Add(port.FCIDList[0]);
item1.SubItems.Add(port.WWPNList[0]);
item1.SubItems.Add(port.TextSerializePortName());
this.ResultsListView.Items.Add(item1);
}
}
However, I get a run-time error basically saying that I have a duplicate item in the list. That makes sense. I am attempting to group by the dictinoary key (the switch name). Is there a way to somehow group the items in the listview, or dynamically add Listviews to the GroupBox on the fly? Basically add a new ListView for each key in the Dictionary? I am still learning C# and forms are still new.
you could use LINQ lookup to group by your key selector.
and extend your portpair to enumerable when add to into listview subitems
This is the code snippet I did sometimes hopefully could help you.
Dictionary<String, Country> dict = new Dictionary<string, Country>();
dict.Add("Toronto", Country.Canada);
dict.Add("New York", Country.US);
dict.Add("Vancover", Country.Canada);
dict.Add("Seattle", Country.US);
dict.Add("Fredericton", Country.Canada);
Lookup<Country,String> lookup = (Lookup<Country,String>) dict.ToLookup(pair =>pair.Value, pair => pair.Key);
foreach (var countryGroup in lookup)
{
item = new ListViewItem(countryGroup.Key.ToString());
item.SubItems.Add(string.Format("{0}", string.Join(",", countryGroup.Select(s => "#" + s))));
lv.Items.Add(item);
item = null;
}

How do I get a usabled List object for this code in C# using LINQ to XML?

Newbie to C# here....
I have the following code:
var xdoc = XDocument.Parse(xml);
var result = xdoc.Root.Elements("item")
.Select(itemElem => itemElem.Elements().ToDictionary(e => e.Name.LocalName, e => e.Value))
.ToList();
but when I try to use result as I would any List object, such as result.Item, it doesn't work.
What am I doing wrong? Why is result not coming back as a normal List object that I can manipluate in my code? Do I need to make another List object from it?
I am just trying to get the first Dictionary item out of the List and use it.
It depends on what you expected. Your code currently produces a List<Dictionary<string,string>>. So each entry in the list would be a dictionary.
You can access each dictionary as you usually would access list elements, i.e.
string firstResult = result[0]["key"];
The first part [0] is the indexer of the list the second part ["key"] is the indexer of the dictionary - this would return the value for the key "key" of the first dictionary in your list.
This assumes the list has at least one entry though for which you would have to check.
This is a List<Dictionary<String, String>>. Each element in the list is a Dictionary.
It would help to know what you wanted to do with it.
But some examples are:
//Get the First Dictionary Item, then Iterate through all the items in the first dictionary.
var firstItem = results.First();
foreach(var kvPair in firstItem)
{
var key = kvPair.Key;
var val = kvPair.Value;
}
//Loop through each Dictionary getting values from each.
foreach (var result in results)
{
var wordValue = result["word"];
var defValue = result["def"];
}
//Create a list of all the values for the Elements with the key "word".
var valuesForAllWords =
results
.Select(r => r["word"])

Categories