Problems with Lists and Dictionaries - c#

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);

Related

C# Most elegant way to convert string array to dictionary with different keys

I have a collection of string arrays (result of splitting CSV to rows and then delimiting)
{31001, 2014-01-01, 24:00:00},{31001, 2014-01-02, 24:00:00},{31001, 2014-01-03, 24:00:00} ...
Now I need to convert it to list of dictionaries, where each dictionary element will have custom key depending on arrays element index. So I want to achieve something like this:
{
{"Index":"31001", "Date":"2014-01-01", "Time":"24:00:00"},
{"Index":"31001", "Date":"2014-01-02", "Time":"24:00:00"},
{"Index":"31001", "Date":"2014-01-03", "Time":"24:00:00"},
...
}
I can't use models for this
Assuming you will have duplicate keys you could use something like
List<KeyValuePair<string,Tuple<string,string>>
where the key is the Index and the rest of the data belongs in the Tuple (Date,Time,..etc).
If you will have more data you couls simply use a List<KeyValuePair<string,List<string>>>
You could do it with an anonymous object.
this way would result in objList having all the rows with the properties Index,Date and Time. whilst not using named classes.
(please note I'm still learning if I don't name things right)
List<Object> objList = new List<object>();
foreach(var line in lines)
{
var fields = line.Split(',');
objList.Add(new {
Index = fields[0],
Date = fields[1],
Time=fields[2]
});
}

How to get Distinct keys of all child dictionary elements of all parent dictionary values

I have a dictionary like this...
Dictionary<string, Dictionary<string, double>>
How to get the list of all Distinct or unique child dictionary keys from all dictionaries of all parent dictionary values (parent dictionary values is nothing but child dictionaries)?
which is the fastest way of doing this in C#?
It's really easy using LINQ:
var result = myDict.Values.SelectMany(x => x.Keys)
.Concat(myDict.Keys)
.Distinct()
.ToList();
but even without LINQ it's super easy when you use HashSet<string>:
var set = new HashSet<string>();
foreach(var outerItem in myDict)
{
set.Add(outerItem.Key);
foreach(var innerKey in item.Value.Keys)
{
set.Add(innerKey);
}
}
HashSet<T> will only keep distinct items, so adding the same string twice won't make any difference.
PS. Next time you should try writing the code first, and ask question when you run into issue you can't overcome by yourself. Stack Overflow is not 'I want code, give me code' kind of site.
Then you need to call SelectMany() on Values property of your dictionary and then use Distinct() to get distinct elements from a sequence by using the default equality comparer.
var res = myDict.Values.SelectMany(x => x.Keys).Distinct().ToList();
This code creates a Dictionary with string keys and double values.
Dictionary<string, double> d = new Dictionary<string, double>()
{
};
// Store keys in a List
List<string> list = new List<string>(d.Keys);
// Loop through list
foreach (string k in list)
{
//From here you can choose distinct key
}
If I'm reading this right:
IEnumerable<string> uniqueChildKeys = dictOfDicts
.SelectMany(d => d.Value.Keys)
.Distinct();

Sort Dictionary based on values in a list of integers

I'm having a problem sorting a dictionary based on the sum of 1s in lists of integers inside the same Dictionary. So first I want to count the 1s in each list and then sort the dictionary based on the result.
I've found some solutions in Stackoverflow but they don't answer my question.
Th dictionary looks like the following:
Dictionary<int, List<int>> myDic = new Dictionary<int, List<int>>();
List<int> myList = new List<int>();
myList = new List<int>();//Should appear third
myList.Add(0);
myList.Add(0);
myList.Add(1);
myDic.Add(0, myList);
myList = new List<int>();//Should appear second
myList.Add(1);
myList.Add(1);
myList.Add(0);
myDic.Add(1, myList);
myList = new List<int>();//Should appear first
myList.Add(1);
myList.Add(1);
myList.Add(1);
myDic.Add(2, myList);
I tried this code but it seems it doesn't do anything.
List<KeyValuePair<int, List<int>>> myList2 = myDic.ToList();
myList2.Sort((firstPair, nextPair) =>
{
return firstPair.Value.Where(i=>i==1).Sum().CompareTo(nextPair.Value.Where(x=>x==1).Sum());
});
You are sorting list items in ascending order. I.e. items with more 1s will go to the end of list. You should use descending order. Just compare nextPair to firstPair (or change sign of comparison result):
myList2.Sort((firstPair, nextPair) =>
{
return nextPair.Value.Where(i => i==1).Sum().CompareTo(
firstPair.Value.Where(x => x==1).Sum());
});
This approach has one problem - sum of 1s in value will be calculated each time two items are compared. Better use Enumerable.OrderByDescending. It's more simple to use, and it will compute comparison values (i.e. keys) only once. Thus Dictionary is a enumerable of KeyValuePairs, you can use OrderByDescending directly with dictionary:
var result = myDic.OrderByDescending(kvp => kvp.Value.Where(i => i == 1).Sum());
Your sort is backward, which is why you think it's not doing anything. Reverse the firstPair/nextPair values in your lambda and you'll get the result you expect.
Though, #Sergey Berezovskiy is correct, you could just use OrderBy, your example code could benefit from perhaps a different pattern overall.
class SummedKV
{
public KeyValuePair Kvp {get; set;}
public int Sum {get; set;}
}
var myList =
myDic.ToList()
.Select(kvp=> new SummedKV {Kvp = kvp, Sum = kvp.Value.Sum() });
myList.Sort(skv=>skv.Sum);
Maybe something simpler
myList2.OrderByDescending(x => x.Value.Sum());
Your code does do something. it creates a list of the items that used to be in the dictionary, sorted based on the number of 1 items contained in the list. The code that you have correctly creates this list and sorts it as your requirements say it should. (Note that using OrderByDescending would let you do the same thing more simply.)
It has no effect on the dictionary that you pulled the lists out of, of course. Dictionaries are unordered, so you can't "reorder" the items even if you wanted to. If it were some different type of ordered collection then it would be possible to change the order of it's items, but just creating a new structure and ordering that wouldn't do it; you'd need to use some sort of operation on the collection itself to change the order of the items.

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