Adding lists to a nested list dictionary - c#

I'm trying to create and fill a dictionary that contains a list as it's value; i.e.
Dictionary <string, List<string>> DictionaryA = new Dictionary<string,List<string>>();
The values in the dictionary are then going to be output into an Excel spreadsheet.
The issue arises when I am trying to input lists into the Dictionary under a Key. The first Dictionary assignment is fine, for example a list of 10 strings under the Key "Key1".
Dictionary <string, List<string>> DictionaryA = new Dictionary<string, List<string>>();
int i = 0;
while(page.MoveNext()) //For example, for each page in a book
{
while(words.MoveNext()) //For example, words in the page
{
if(!(ListA.Contains(ValueA)) //For example, we are looking to store instances of each word in each page of a book
{
ListA.Add(ValueA);
}
DictionaryA.Add(i, ListA);
i++;
}
sortedList = DictionaryA.Keys.ToList(); //Let's say we want to sort the Dictionary as well
sortedList.Sort()
foreach (var key in sortedList)
{
DictionaryASorted.Add(key, DictionaryA[key]);
}
ExcelOuput(DictionaryASorted); //Function to export and save an Excel File
}
So the first run through page.Movenext() loop is fine, the Dictionary is filled correctly with the list. However, on the second run through of the loop, any unique "ValueA" that is found is added to the list "ListA" - this modifies the "ListA" that is already stored in the Dictionary. The end result is a Dictionary that contains the different page numbers as keys, and the same huge List of words for each of those keys.
If I use ListA.Clear() at the beginning of each page loop, the List ends up being the words from the last page it reads and nothing else.
How can I use this nested List without changing the previous List being modified? Am I trying to do this the right way? Or is there a better, more elegant solution to this?

You need to creat a new list in the loop.
So, just above while(words.MoveNext())
You need:
List<string> ListA = new List<string>();
This will create a new list for you to populate. You have to realize that the dictionary and ListA are both pointing at the same list. Adding or clearing the list does the same to the list the dictionary refferences. You need to create a new list for each dictionary value.

Related

Inserting the first value of a key-value pair, when the value is a list

I have a dictionary as below, where the key is a string and the value is a list of doubles:
Dictionary<string, List<double>> dataStore = new Dictionary<string, List<double>>();
List<string> channel_names = new List<string>(); // contains the keys
Now when I want to add data to this dictionary, I do:
if (dataStore.ContainsKey(channel_names[j]))
{
dataStore[channel_names[j]].Add(measurement);
}
else
{
dataStore.Add(channel_names[j], new List<double>((int)measurement));
}
The first statement (adding to an existing key) works fine, but something is wrong with the second statement, i.e. when I am trying to initialise the keys with the first double in the list. The first measurement is being missed out. Can anyone please advise as to why?
Thanks
You are using the constructor List(int), where int specifies the initial capacity of the list; it does not add that number to the list.
You could instead use collection-initialiser syntax:
new List<double> { measurement }
You can refactor your code to this solution:
if (!dataStore.ContainsKey(channel_names[j]))
{
dataStore.Add(channel_names[j], new List<double>());
}
dataStore[channel_names[j]].Add(measurement);
It will make it clearer that the measurment is always added to the list, regardless of the result of the ContainsKey method.
There are two constructors for List<T> that do different things.
When you call new List<T>(int) you create a new list of the provided size - or more exact the initial capacity of that list.
When you want to create and fill a new list in one go, you should use a collection-initializer:
dataStore.Add(channel_names[j], new List<double> { measurement });
As an asside you can simplify your code:
if (!dataStore.ContainsKey(channel_names[j]))
{
dataStore[channel_names[j]] = new List<int>();
}
dataStore[channel_names[j]].Add(measurement);
As I mention in the comments and others have mentioned, you aren't adding things to the list when you construct it, you are allocating capacity to the list. The code you want is:
if (!dataStore.ContainsKey(channel_names[j]))
{
dataStore.Add(channel_names[j], new List<double>();
}
dataStore[channel_names[j]].Add(measurement);
If the Dictionary doesn't contain the key you want, you create a new list and add it to the dictionary. At this point, the dictionary necessarily contains the appropriate key (it either already existed and you skipped the if block, or it didn't exist and you created it). In any case, at that point, you can just add the measurement to the appropriate list.
You have two alternatives:
If you have list for given key, just add measurement to the existing value (which is list)
If dataStore doesn't have the key, you should add entire key-value pair: key (channel_names[j]) and value which is list with one item
Code:
if (dataStore.TryGetValue(channel_names[j], out var list))
// the key exists; just add measurement to the existing list
list.Add(measurement);
else
// no key found; add key-value pair: key and a list with one item
dataStore.Add(channel_names[j], new List<double>() {measurement});
The constructor on List<T> which takes an integer is not adding that integer to the list. It is setting the capacity of the list.
Instead you could use an initializer...
dataStore.Add(channel_names[j], new List<double>() { measurement };
Alternatively, you could use Dictionary.TryGetValue to find the List<double> for the given string, add it if it doesn't exist, then just modify it.
List<double> values = null;
if (!dataStore.TryGetValue(channel_names[j], out values))
{
values = new List<double>();
dataStore.Add(channel_names[j], values);
}
values.Add(measurement);

My code adds only a single key value pair of values while I require list of values to be added. How can I add the entire list?

I am trying to add a list of values in a dictionary variable. The dictionary contains a string and a list of recommendations as a key value pair. See the below code as an example:
Dictionary<string, List<Recommendations>> rec = new Dictionary<string, List<Recommendations>>();
List<Recommendations> ItemsList = db.Items.ToLIst();
// Here I have added all the items to dictionary as follows
rec.Add(name, ItemsList);
//And Here I want to filter the results as follows :
var OrderedList = rec.Where(x=>x.Key!=name)
The Problem is that Ordered list only gets a single key Value pair while I want a List of Key value pairs Which I am going to iterate in the following code as follows.
List<Recommendations> Recommendations = new Recommendations();
foreach(entry in OrderedList)
{
Recommendations.Add(Name=entry.Key,
Rating=CalculateScore(arguments));
}
Uptill Now foreach part works fine but OrderedList should bring all the results from the db. Please tell me how can I do it. I have tried using an array but it does not iterate and add all the records to dictionary list. I want a list of Dictionaries in the OrderedList which in this case is a KeyValuePair Enumerable.

Problems with Lists and Dictionaries

I'm having a problem with a Dictionary of Lists for both the Key and Value.
My dictionary is set up as this
Dictionary<List<string>,List<double>> f = new Dictionary<List<string>,List<double>>();
(it's like this for a very specific reason).
My problem is how to get the two lists out into their own lists. I have tried the following
List<string> s = new List<string>(f.Keys);
List<string> s = f.Select(kvp=>kvp.Keys).ToList()
List<string> s = f.Select(kvp=>kvp.Keys);
List<string> s = f.Keys;
as well as a variant using IEnumerable. No matter what I do, I can't seem to retrieve the Keys (or using f.Values, the values).
Any help here would be appreciated.
A list of strings seems like a VERY odd key for a dictionary, and will have complexities of its own, but you seem confident that it's correct, so I'll focus on your actual question.
Since Keys is a collection of key values, each of which is a List<string>, any of these should work:
List<List<string>> s = f.Select(kvp=>kvp.Key).ToList();
List<List<string>> s = f.Keys.ToList();
If you want ALL strings as a single list (essentially joining all of the lists together), you can use:
List<string> s2 = f.SelectMany(kvp => kvp.Key).ToList();
The SelectMany essentially selects each item from the collection within each key across the whole dictionary.
Lol This is probably the funniest thing I've seen in a while.
Alright. In c# there is a structure called KeyValuePair<TKey, TValue>. You can then iterate through the entire dataset with foreach and get access to what you want.
foreach(KeyValuePair<<List<string>,List<double>> item in f) {
List<string> key = item.key;
List<double> value = item.value;
}
If you have only 1 key,meaning 1 list of strings:
List<string> newf = f.Keys.ElementAt(0);
If you have more place another index.
Or check if the list as some item so that would be the list to retrieve:
List<string> newf = f.Keys.Single(k => k.Contains("SomeString"));
//this must exist or it will throw exception.
Get a key by checking if the corresponding values sum is above(or less,or equal...)
var newf1 = f.Where(k => k.Value.Sum() > 10).Select(v => v.Key);

nested hashset of lists?

I'm working on one of the project Euler problems, and I wanted to take the approach of creating a list of values, and adding the list to a Hashset, this way I could evaluate in constant time if the list already exists in the hashset, with the end goal to count the number of lists in the hashset for my end result.
The problem I'm having is when I create a list in this manner.
HashSet<List<int>> finalList = new HashSet<List<int>>();
List<int> candidate = new List<int>();
candidate.Add(5);
finalList.Add(candidate);
if (finalList.Contains(candidate) == false) finalList.Add(candidate);
candidate.Clear();
//try next value
Obviously the finalList[0] item is cleared when I clear the candidate and is not giving me the desired result. Is it possible to have a hashset of lists(of integers) like this? How would I ensure a new list is instantiated each time and added as a new item to the hashset, perhaps say in a for loop testing many values and possible list combinations?
Why don't you use a value which is unique for each list as a key or identifier? You could create a HashSet for your keys which will unlock your lists.
You can use a Dictionary instead. The only thing is you have to test to see if the Dictionary already has the list. This is easy to do, by creating a simple class that supports this need.
class TheSimpleListManager
{
private Dictionary<String, List<Int32>> Lists = new Dictionary<String, List<Int32>>();
public void AddList(String key, List<Int32> list)
{
if(!Lists.ContainsKey(key))
{
Lists.Add(key, list);
}
else
{
// list already exists....
}
}
}
This is just a quick sample of an approach.
To fix your clear issue: Since its an object reference, you would have to create a new List and add it to the HashSet.
You can create the new List by passing the old one into its constructor.
HashSet<List<int>> finalList = new HashSet<List<int>>();
List<int> candidate = new List<int>();
candidate.Add(5);
var newList = new List<int>(candidate);
finalList.Add(newList);
if (finalList.Contains(newList) == false) //Not required for HashSet
finalList.Add(newList);
candidate.Clear();
NOTE: HashSet internally does a contains before adding items. In otherwords, here even if you execute finalList.Add(newList); n times, it would add newList only once. Therefore it is not necessary to do a contains check.

Can Dictionary values be populated through a list without looping?

Can we have something like -
Dictionary<string, string> dict = new Dictionary<string, string>();
List<string> keysList= new List<string>();
List<string>valuesList= new List<string>();
//Assuming both the list have the same number of items
dict.keys = keysList;
dict.values = valuesList;
Mostly, I want to know if there is a way to populate the keys and values by directly assigning them to a list?
Mostly, I want to know if there is a way to populate the keys and values by directly assigning them to a list?
No, but just zip them and then use ToDictionary:
var dict = keysList.Zip(valuesList, (key, value) => Tuple.Create(key, value))
.ToDictionary(pair => pair.Item1, pair => pair.Item2);
A dictionary, internally isn't storing the data as two lists. It's storing the data in a hash table, which means it need to take each key, generate a hash for it, and then place the item at the location that corresponding to that hash. Because of this the only way to add a group of items is just to loop through the group and add each item. You can use the LINQ ToDictionary method, as mentioned in another answer, but internally all it's going to do is loop through each item and add it to the dictionary. This prevents you from seeing the loop, but the loop is still there.

Categories

Resources