I have below code which adds Dictionary data to List of IDictionary as shown below
var datalist = new List<IDictionary<string, string>>();
var data = new Dictionary<string, string>();
for (var i = 0; i < dataTable.Rows.Count; ++i)
{
foreach (var name in arrColumnNames)
{
data[name] = Convert.ToString(dataTable.Rows[i][name]);
}
datalist.Add(data);
}
Now, issue is that my datalist keeps on updating last data values in entire List of datalist. What's wrong? How to keep data values preserved in datalist?
My Spidey Senses tells me you are new'ing this up for every method call, In short, the problem seems like you are creating a new list every time. However i could be completely wrong
Try this in your class, and remove it from the method
Class field
private List<IDictionary<string, string>> datalist = new List<IDictionary<string, string>>();
Method body
Assuming your arrColumnNames is an instantiated List of string
You could do this with Linq
var dict = dataTable.Rows
.Cast<DataColumnCollection>()
.Select(row => arrColumnNames.ToDictionary(x => x, x => row[x].ToString()))
.ToList();
datalist.AddRange(dict);
Footnote : i think this is all a little-bit suspect. Are you sure you want a Dictionary in a List, and not a Dictionary of Key and List
I think what you can do is get a shallow copy of the dictionary after you add the data to the list, try this
var datalist = new List<IDictionary<string, string>>();
var data = new Dictionary<string, string>();
for (var i = 0; i < dataTable.Rows.Count; ++i)
{
foreach (var name in arrColumnNames)
{
data[name] = Convert.ToString(dataTable.Rows[i][name]);
}
datalist.Add(data);
data = new Dictionary<string, string>(data);
}
var datalist = new List<IDictionary<string, string>>();
for (var i = 0; i < dataTable.Rows.Count; ++i)
{
var data = new Dictionary<string, string>();
foreach (var name in arrColumnNames)
{
data[name] = Convert.ToString(dataTable.Rows[i][name]);
}
datalist.Add(data);
}
Moved Dictionary Declaration inside for loop ,so that each data table it creates new object of dictionary and add all the Columns. Otherwise Dictionary keeps last datable Column details
You are only creating a single instance of a Dictionary (outside the for loop), and adding the same instance of it for each row inside the loop.
As it stands, your list will end up being a list of references to the same dictionary, and since the final row in the table has the same columns as all the other rows, you end up with what would look like a list of dictionaries all with the values from the last row. But in fact it's a list where each entry points at the same dictionary, which only contains values from the last row because it has overwritten all the previous values.
If you move the line initializing data inside the for loop, you will end up with a list (one entry for each row) of dictionaries where the key is the column name and the value is the value for that column for that row.
You have to move
var data = new Dictionary<string, string>();
Into
for (var i = 0; i < dataTable.Rows.Count; ++i)
Before the foreach loop.
Related
Because the original post (Create List with name from variable) was so old, I didn't want to approach this as an answer.
But, I wanted to add this use of the above solution because it was non-obvious to me. And, it may help some of my fellow noobs... Also, I ran into some issues I don't know how to address.
I needed a way to create a list using a variable name, in this case "mstrClock", for timing diagrams.
I was not able to get .NET to accept a two-column list, though, so I ended up with two dictionaries.
Is there a way to structure this so that I can use a single dictionary for both columns?
dictD.Add("mstrClock", new List<double>());
dictL.Add("mstrClock", new List<string>());
Then as I develop the timing diagram, I add to the lists as follows:
dictD["mstrClock"].Add(x); // This value will normally be the time value.
dictL["mstrClock"].Add("L"); // This value will be the "L", "F" or "H" logic level
Then to get at the data I did this:
for (int n = 0; n < dictD["mstrClock"].Count; n++)
{
listBox1.Items.Add(dictL["mstrClock"][n] + "\t" + dictD["mstrClock"][n].ToString());
}
Why not just store what you want to display, in the dictionary?
dict.Add("mstrClock", new List<string>());
dict["mstrClock"].Add($"L\t{x}");
for (int n = 0; n < dict["mstrClock"].Count; n++)
{
listBox1.Items.Add(dict["mstrClock"][n]);
}
On another point, do you even need a dictionary? What is the point of having a dictionary with one key? If you only need a List<string>, then only create that.
var items = new List<string>());
items.Add($"L\t{x}");
foreach (var item in items)
{
listBox1.Items.Add(item);
}
You can use Tuples in modern C# to create your two-column list as follows:
var list = new List<(double time, string logicLevel)>();
list.Add((1, "L"));
list.Add((2, "F"));
foreach (var element in list)
{
listBox1.Items.Add($"{element.time} \t {element.logicLevel}");
}
If using a dictionary is a must, you can change the above code to something like:
var dict = new Dictionary<string, List<(double time, string logicLevel)>>();
dict["mstrClock"] = new List<(double time, string logicLevel)>();
dict["mstrClock"].Add((1, "L"));
dict["mstrClock"].Add((2, "F"));
var list = dict["mstrClock"];
foreach (var element in list)
{
listBox1.Items.Add($"{element.time} \t {element.logicLevel}");
}
One approach to creating a 2-column list would be to create a list of key/value pairs:
var list = new List<KeyValuePair<double, string>();
list.Add(new KeyValuePair<double, string>(1, "L");
foreach (KeyValuePair<double, string> element in list)
{
listBox1.Items.Add($"{element.key} \t {element.value}");
}
Right now I have a dictionary being populated with an account as key, and a List as value. I believe my code is working to populate it. But my next step is to iterate through that List associated with a particularly key and do stuff with the list (get sums for each field). I am not that familiar with dictionaries so I am not sure how to access the values and perform an action. I would like to do this summation and print it out in my for each loop, when I exit the while loop.
1) If I could figure out how to access each field in DataRecords (inside the foreach loop), I could likely figure out how to do the summation.
2) Also looking for a way to print the values so I can see if it is even populated correctly.
static void Main(string[] args)
{
Dictionary<string, List<DataRecord>> vSummaryResults = new Dictionary<string, List<DataRecord>>();
while (!r.EndOfStream)
{
if (control == "1")
{
// Need to add List<Datarecords> into dictionary...
if (vSummaryResults.ContainsKey(records.account))
{
vSummaryResults[records.account].Add(records);
}
else
{
vSummaryResults.Add(records.account, new List<DataRecord>());
vSummaryResults[records.account].Add(records);
}
}
}
foreach (List<DataRecord> rec in vSummaryResults.Values)
{
Console.WriteLine(rec.); dictionary.
}
vWriteFile.Close();
Console.ReadLine();
}
Here is my DataRecord class that I am using as the object in the List.
public class DataRecord
{
fields.....
}
For iterations over a dictionary, we use KeyValuePair:
foreach (KeyValuePair<string, List<DataRecord>> kvp in vSummaryResults)
{
string key = kvp.Key;
List<DataRecord> list = kvp.Value;
Console.WriteLine("Key = {0}, contains {1} values:", key, list.Count);
foreach (DataRecord rec in list)
{
Console.WriteLine(" - Value = {0}", rec.ToString()); // or whatever you do to put list value on the output
}
}
You need another loop inside the first to get values in your list.
foreach (List<DataRecord> rec in vSummaryResults.Values)
{
foreach(DataRecord data in rec)
{
Console.WriteLine(data .YourProperty);
}
}
If you know the key:
foreach (List<DataRecord> rec in vSummaryResults[key])
{
foreach(DataRecord data in rec)
{
Console.WriteLine(data .YourProperty);
}
}
I made an example with a simple situation. Its a list of strings, but you can do the object.ToString() to get some tekst;
To loop over the list contained by the key you need to iterate over that list again that is what the 2nd foreach does.
Dictionary<string, List<string>> dictionary = new Dictionary<string, List<string>>();
List<String> ls = new List<string>();
ls.Add("item1");
ls.Add("item2");
dictionary.Add("it1", ls);
dictionary.Add("it2", ls);
foreach (var item in dictionary)
{
foreach(var it in item.Value)
{
Console.WriteLine(it);
}
}
You have a dictionary
Dictionary<string, List<DataRecord>> vSummaryResults = new Dictionary<string, List<DataRecord>>();
You could do a
foreach (List<DataRecord> recs in vSummaryResults.Values)
{
foreach (DataRecord rec in recs)
Console.WriteLine(rec.Something);
}
You haven't specified what DataRecord looks like, but you would get a list of list. There's probably a lovely Linq expression that could do the same.
I understand it from reading your code, you have a dictionary where each key has a list of type DataRecord.
With your current loop
foreach (List<DataRecord> rec in vSummaryResults.Values)
{
Console.WriteLine(rec.); dictionary.
}
You looped through each List of type DataRecord. To access the data stored in each object in each list you will need to include another foreach loop to loop through the objects in the list.
foreach (var rec in vSummaryResults.Values)
{
// At this point we have access to each individual List<DataRecord>
foreach(var SingleDataRecordObj in rec)
Console.WriteLine(ingleDataRecordObj.membervariablename)
//From here we are able to list the individual variable member names of values that are in the DataRecord data type, showing all of the information in each list that is stored in the values of the dictionary
}
You can't modify the data in the foreach loop, but you could add them a more simple data structure to perform whatever commutation you wanted etc.
Here is the code for exactly what I needed to do. Working the way I need it to now, thanks for everyone's help.
int iSumOpen = 0;
foreach (KeyValuePair<string, List<DataRecord>> kvp in vSummaryResults)
{
string key = kvp.Key; //assigns key
List<DataRecord> list = kvp.Value; //assigns value
Console.WriteLine("Key = {0}", key);
iSumOpen = 0;
foreach (DataRecord rec in list)
{
if (vSummaryResults.ContainsKey(key))
{
iSumOpen += rec.open;
}
else
{
vSummaryResults.Add(key, list);
}
}
Console.WriteLine(iSumOpen);
}
I have a function that returns a Hashtable. The var dt gets a bunch of RevenueGroupIDs and ProductIDs from the database that map together in a 1-to-many structure. For example:
RevenueGroupID ProductID
1 312
1 313
1 315
2 317
2 319
3 401
3 410
3 411
3 415
The combination of these 2 numbers are always unique -- no repeats. The function builds a Hashtable dictionary of key-value pairs in which the key is always a RevenueGroupID and the value is a List<int> of all the ProductIDs for that RevenueGroupID. The problem is: each time a key-value pair is added, all previous key-value pairs get overwritten with the current one. So at the end, ALL key value pairs are identical to the final one. I have stepped through the code and verified that each key-value pair is correct and unique. I can't see any reason for the reset. I have looked suspiciously at "productIDs.Clear();", but I can't see why that would be messing up the hashtable.
public static Hashtable GetAllProductIDsInAllRevenueGroups()
{
var productIDs = new List<int>();
var ht = new Hashtable();
string sql = #" {my sql here}";
var dt = Utilities.GetDataTableForQuery(sql, null);
int counter = 0;
int revenueGroupID = 0;
int lastRevenueGroupID = 0;
foreach (DataRow row in dt.Rows)
{
revenueGroupID = Utilities.SafeInt(row["RevenueGroupID"]);
int productID = Utilities.SafeInt(row["ProductID"]);
if (revenueGroupID != lastRevenueGroupID && counter > 0)
{
ht.Add(lastRevenueGroupID, productIDs);
productIDs.Clear();
}
productIDs.Add(productID);
lastRevenueGroupID = revenueGroupID;
counter++;
}
ht.Add(lastRevenueGroupID, productIDs);
return ht;
}
This is because you keep adding productIDs list to a hash table without making a copy, and then clear the content:
ht.Add(lastRevenueGroupID, productIDs);
productIDs.Clear(); // This removes all entries from the item stored at the lastRevenueGroupID key
This means that the same object is added over and over again, so you end up with multiple copies of the list that has the content of the last entry.
An easy fix is to make a new list before adding it to hash table, like this:
ht.Add(lastRevenueGroupID, productIDs.ToList());
productIDs.Clear();
The problem is that you are only using one list instead of creating a new list for each item. Adding the list to the hash table doesn't create a copy of the list, it just adds the reference. When you clear the list you will clear the list for all previously added items in the hash table, because they are all the same list.
You can create a new list and add to the hash table when you start a new group. As you keep the reference to the list, you can keep adding numbers to it after it is places in the hash table:
public static Hashtable GetAllProductIDsInAllRevenueGroups()
{
var productIDs;
var ht = new Hashtable();
string sql = #" {my sql here}";
var dt = Utilities.GetDataTableForQuery(sql, null);
int counter = 0;
int revenueGroupID = 0;
int lastRevenueGroupID = 0;
foreach (DataRow row in dt.Rows)
{
revenueGroupID = Utilities.SafeInt(row["RevenueGroupID"]);
int productID = Utilities.SafeInt(row["ProductID"]);
if (counter == 0 || revenueGroupID != lastRevenueGroupID)
{
productIDs = new List<int>();
ht.Add(revenueGroupID, productIDs);
}
productIDs.Add(productID);
lastRevenueGroupID = revenueGroupID;
counter++;
}
return ht;
}
Note: Consider using the strictly typed Dictionary<int, List<int>> instead of Hashtable.
I have a List and a ListItemCollection and want to check if there have the same elements.
First, I fill the ListItemCollection with Text and Value. (After a SQL Select)
ListItemCollection tempListName = new ListItemCollection();
ListItem temp_ListItem;
if (reader.HasRows)
{
while (reader.Read())
{
temp_ListItem = new ListItem(reader[1].ToString(), reader[0].ToString());
tempListName.Add(temp_ListItem);
}
}
and I have the List
List<string> tempList = new List<string>(ProfileArray);
with some values like {"1","4","5","7"}
now, I want to check, if the tempList have maybe some elements with the same value in tempListName and read the text from the value adn write it in a new list.
Note: Im using asp.net 2.0.
List.FindAll was already available in C# 2.0:
List<string> newList = tempList.FindAll(s => tempListName.FindByText(s) != null);
ListItemCollection.FindByText:
Use the FindByText method to search the collection for a ListItem with
a Text property that equals text specified by the text parameter. This
method performs a case-sensitive and culture-insensitive comparison.
This method does not do partial searches or wildcard searches. If an
item is not found in the collection using this criteria, null is
returned.
Real simple solution that you can customize and optimize as per your needs.
List<string> names = new List<string>(); // This will hold text for matched items found
foreach (ListItem item in tempListName)
{
foreach (string value in tempList)
{
if (value == item.Value)
{
names.Add(item.Text);
}
}
}
So, for a real simple example, consider something like this:
List<string> tempTextList = new List<string>();
while (reader.Read())
{
string val = reader[0].ToString(),
text = reader[1].ToString();
if (tempList.Contains(val)) { tempTextList.Add(text); }
temp_ListItem = new ListItem(text, val);
tempListName.Add(temp_ListItem);
}
Now, just having a listing of the text values doesn't do you much good, so let's improve that a little:
Dictionary<string, string> tempTextList = new Dictionary<string, string>();
while (reader.Read())
{
string val = reader[0].ToString(),
text = reader[1].ToString();
if (tempList.Contains(val)) { tempTextList.Add(val, text); }
temp_ListItem = new ListItem(text, val);
tempListName.Add(temp_ListItem);
}
Now you can actually find the text for a specific value from the dictionary. You might even want to declare that Dictionary<string, string> in a higher scope and use it elsewhere. If you were to declare it at a higher scope, you'd just change one line, this:
Dictionary<string, string> tempTextList = new Dictionary<string, string>();
to this:
tempTextList = new Dictionary<string, string>();
var resultList = new List<string>();
foreach (string listItem in tempList)
foreach (ListItem listNameItem in tempListName)
if (listNameItem.Value.Equals(listItem))
resultList.Add(listNameItem.Text);
Dictionary<int, String> loadData = new Dictionary();
// File contains a list of filenames say for ex. 5 filenames
foreach (var file in filenames)
{
// I want to assign like this
loadData[id]=file;
}
How can I assign loadData(key,value) in C# so that I can access like loadData[5] = "hello.txt";
First: You are using new Dictionary() which won't properly work. Use new Dictionary<int, String>() instead.
Second: Where does id come from? If it's just a counter, you can do the following:
Dictionary<int, String> loadData = new Dictionary<int, String>();
int id = 0;
foreach (string file in filenames)
{
loadData.Add(id++, file);
}
if id is just a counter you can use arrays and still can write loadData[5]="hello.txt";
var loadData = filenames.ToArray();
loadData[5]="hello.txt";
Keep a counter.
int i = 0;
foreach (var file in filenames) {
++i;
loadData[i] = file;
}
This assigns the first item in filenames to loadData[1].
I assume by ID, it's not a value in file but the item's index in the loop
filenames.ForEach(x => loadData.Add(loadData.Count, x));
This will give you
Key Value
0 First filename
1 Second filename
2 Third filename
etc...
If I understand correctly, this is what you want. Or do you have a separate Key and want to access the dictionary by some sort of index (like a List)?
This is very easy.
You can use this.
loadData.Add(1,"fileName1");
Or You Put this line inside loop.
Another way of doing it.
var loadData = fileNames
.Select((fn,index)=> new {key = index, value = fn})
.ToDictionary(x=> x.key, x=> x.value);
Using the ToDictionary() extension method...
int id = 1;
var loadData = filenames.ToDictionary(x => id++);