How List<T> works with Dictionary<K, List<T>>? - c#

var solutions = new Dictionary<int, List<Tuple<int, int>>>();
List<Tuple<int, int>> list = null;
var z = solutions.TryGetValue(sum, out list);
if (!z)
{
list = new List<Tuple<int, int>>();
solutions.Add(sum, list);
}
list.Add(new Tuple<int, int>(a, b));
I don't understand why when I add element to list (last line) it change corresponding key-value in dictionary?

You don't change key value pair in dictionary by adding element to list. You are changing the list. And dictionary is just holding reference to that list so it appears to change.

Related

How to get from Dictionary<char, Tuple <int, char>> int value for specific key?

I have 2 dictionaries in the first case I used Tuple for key values and it works fine like this
Dictionary<Tuple<char, char>, int> pairPoints = new Dictionary<Tuple<char, char>, int>();
foreach (var items in this.pairPoints)
Console.WriteLine(items.Key.Item1);
but in the second case, I want to get a value which is also in Tuple {int,char} however I can't find something like result.Values.Item1
Dictionary<char, Tuple <int, char>> result = new Dictionary<char, Tuple<int, char>>();
if(distance < result.Values.Item1) {//do my things}
Is it possible to write it something like this or do I have to use a different array method?
result.Values is a collection of Tuple<int, char>
You can access a single item in the collection by the dictionary key:
result[someChar].Item1
Or you can loop though all the values as follows:
foreach(var tuple in result.Values)
Console.WriteLine(tuple.Item1)
Well you have multiple ways to do this. But you need to understand first that result.Values is a collection and not a single value, that's why you can't access result.Values.Item1.
Check if any result matches:
if(result.Values.Any(t => t.Item1 > distance))
{
}
Or Loop through results that match
foreach(var item in result.Values.Where(t => t.Item1 > distance))
{
// use item.Item1 and item.Item2
}
You are doing this in wrong way. You have to use Value not Values
Correct way:
Dictionary<char, Tuple <int, char>> result = new Dictionary<char, Tuple<int, char>>();
foreach (var items in result)
{
Console.WriteLine(items.Value.Item1);
Console.WriteLine(items.Value.Item2);
}

How can I get the inner list value of list of keyvaluepair of (string, list)?

I am now struggling to find a way to get inner list from complicated List of keyvalupair.
public static List<KeyValuePair<string, List<KeyValuePair<int, string>>>> conditions = new List<KeyValuePair<string, List<KeyValuePair<int, string>>>>();
I want list from above list using given string value as a key.
Can anyone help me please?
You can use FirstOrDefault method like this:
conditions.FirstOrDefault(x => x.Key == "key").Value;
Or you should probably use a Dictionary instead.
You could use a Dictionary and a Dictionary as your value as well.
public static Dictionary<string, Dictionary<int, string>> conditions = new Dictionary<string, Dictionary<int, string>>();
and access it with conditions[key]
For example:
//Initialize random, pointless dictionary for example
var conditions = new Dictionary<string, Dictionary<int, string>>
{
{
"firstDict", new Dictionary<int, string>
{
{1, "blue"},
{2, "red"}
}
},
{
"secondDict", new Dictionary<int, string>
{
{1, "car"},
{2, "truck"}
}
}
};
//Get dictionary with key value "firstDict"
var firstDict = conditions["firstDict"];
//Gets the value associated with key "1"
var color = firstDict[1];

How to search in a dictionary?

I am trying to search in a dictionary.
I have 2 dictionaries:
Dictionary<int, string> dict = new Dictionary<int, string>()
Dictionary<int, int> temp = new Dictionary<int, int>()
then ive populated this dictionary with:
dict.Add(123, "");
dict.Add(124, ""); //and so on
then i want to loop though this dictionary and recall the key and add that to the other dictionary
for (int i = 0; i < dict.Count; i++)
{
if (dict[i] == "")
{
temp.Add(dict[dict.ElementAt(i).Key],0);
dict[dict.ElementAt(i).Value] = "Moved";
}
}
i shall be doing other things inside this forloop so i cannot change that to a foreach loop. I am trying to check if the value of the Dictionary dict is empty then take the Key and copy the key value to the temp dictionary, but i am getting errors.
Please help :)
the problem im trying to solve is that i want to be able to search the dict dictionary for for a value with "" and take the key and store it in another dictionary temp (which will later on hold a second value). i need to do this in a for-loop as i want to be able to go back by changing the value of i.
i want to be able to use i to select both the key and value from the dict dictionary.
The errors i was getting was simply converting from string to int, i cannot get it to even store the key from dict into an int variable.
You need to put a value in the temp dictionary. I chose 0.
Dictionary<int, string> dict = new Dictionary<int, string>();
Dictionary<int, int> temp = new Dictionary<int, int>();
dict.Add(123, "");
dict.Add(124, ""); //and so on
int[] keys = dict.Keys.ToArray();
for (int i = 0; i < dict.Count; i++)
{
if (dict[keys[i]] == "")
{
temp.Add(keys[i],0);
dict[keys[i]] = "Moved";
}
}
I think this is what you're looking for:
Dictionary<int, string> dict = new Dictionary<int, string>();
List<int> temp = new List<int>();
dict.Add(123, "");
dict.Add(124, ""); //and so on
foreach (int key in dict.Keys.ToList())
{
if (dict[key] == "")
{
temp.Add(key);
dict[key] = "Moved";
}
}
}
*
First, notice temp is a List, not a Dictionary, since you're just adding the keys, no key => value (this can be changed if you can better explain why you need this as a dictionary)...
Second, notice I used dict.Keys to get all the keys in the dictionary. I also used ToList() so it can work in the foreach loop...
are you getting a compile error for the dictionary definition
Dictionary<int, int> temp = new Dictionary<int, temp>(); // int, temp?
if so,
Dictionary<int, int> temp = new Dictionary<int, int>(); // int, int
?
or, you're getting an error with this:
temp.Add(dict[dict.ElementAt(i).Key]);
because you're adding just a key, with no value. it would be something like
temp.Add(i, dict[i]); ?
if you're just using temp to hold the key values, you don't want a Dictionary, you probably HashSet (only keys, no keys+values)
if you explain exactly what you're trying to solve, this is probably something you can do trivially with a single linq statement?
Why is temp a dictionary? I would use a List<int> with all keys of the dictionary with an empty(null?) value.
List<int> keysWithEmptyValuesInDictionary = dict
.Where(kvp => string.IsNullOrEmpty(kvp.Value))
.Select(kvp => kvp.Key)
.ToList();
foreach (int key in keysWithEmptyValuesInDictionary)
{
dict[key] = "moved";
}

How to sort the list with duplicate keys?

I have a set of elements/keys which I'm reading from two different config files. So the keys may be same but with different values associated with each of them.
I want to list them in the sorted order. What can I do ? I tried with SortedList class but it does not allow duplicate keys.
How can I do it?
e.g Lets say I have 3 elements with keys 1,2,3. Then i get one more element having key 2 (but different value). Then I want the new key to get inserted after existing key 2 but before 3. If I againg find an element with key 2, then it should go after most recently added key 2.
Please note than I'm using .NET 2.0
I prefer to use LINQ for this type of thing:
using System.Linq;
...
var mySortedList = myList.Orderby(l => l.Key)
.ThenBy(l => l.Value);
foreach (var sortedItem in mySortedList) {
//You'd see each item in the order you specified in the loop here.
}
Note: you must be using .NET 3.5 or later to accomplish this.
what you need is a Sort function with a custom IComparer. What you have now is the default icomparer when you use sort. this will check on a field value.
When you create a custom IComparer (you do this in you class by implementing the Icomparable interface). what it does is: your object checks itself to every other object in the list you sort.
this is done by a function. (don't worry VS will implementd it when refering your interface
public class ThisObjectCLass : IComparable{
public int CompareTo(object obj) {
ThisObjectCLass something = obj as ThisObjectCLass ;
if (something!= null)
if(this.key.CompareTo(object.key) == 0){
//then:
if .....
}
else if(this.value "is more important then(use some logic here)" something.value){
return 1
}
else return -1
else
throw new ArgumentException("I am a dumb little rabid, trying to compare different base classes");
}
}
read on the links above for better information.
I know I had some troubles understanding this myself in the beginning, so for any extra help add a comment and I will elaborate
I did it by creating a SortedList<int, List<string>>. Whenever I find the duplicate key, I simply insert the value in the existing list associated with the key already present in the SortedList object. This way, I can have list of values for a particular key.
Use your own comparer class!
If your keys in the sorted list are integers, you may use for example this comparer:
public class DegreeComparer : IComparer<int>
{
#region IComparer<int> Members
public int Compare(int x, int y)
{
if (x < y)
return -1;
else
return 1;
}
#endregion
}
To instanciate a new SortedList with int keys and string values use:
var mySortedList = new SortedList<int, string>(new DegreeComparer());
If you don't really care about the sequence of the elements with equal keys, add everything to a list and then sort it by key:
static void Main(string[] args)
{
List<KeyValuePair<int, MyClass>> sortedList =
new List<KeyValuePair<int, MyClass>>() {
new KeyValuePair<int, MyClass>(4, new MyClass("four")),
new KeyValuePair<int, MyClass>(7, new MyClass("seven")),
new KeyValuePair<int, MyClass>(5, new MyClass("five")),
new KeyValuePair<int, MyClass>(4, new MyClass("four-b")),
new KeyValuePair<int, MyClass>(7, new MyClass("seven-b"))
};
sortedList.Sort(Compare);
}
static int Compare(KeyValuePair<int, MyClass> a, KeyValuePair<int, MyClass> b)
{
return a.Key.CompareTo(b.Key);
}
If you really want the items inserted later to be after those inserted earlier, sort them as they are inserted:
class Sorter : IComparer<KeyValuePair<int, MyClass>>
{
static void Main(string[] args)
{
List<KeyValuePair<int, MyClass>> sortedList = new List<KeyValuePair<int, MyClass>>();
Sorter sorter = new Sorter();
foreach (KeyValuePair<int, MyClass> kv in new KeyValuePair<int, MyClass>[] {
new KeyValuePair<int, MyClass>(4, new MyClass("four")),
new KeyValuePair<int, MyClass>(7, new MyClass("seven")),
new KeyValuePair<int, MyClass>(5, new MyClass("five")),
new KeyValuePair<int, MyClass>(4, new MyClass("four-b")),
new KeyValuePair<int, MyClass>(4, new MyClass("four-c")),
new KeyValuePair<int, MyClass>(7, new MyClass("seven-b")) })
{
sorter.Insert(sortedList, kv);
}
for (int i = 0; i < sortedList.Count; i++)
{
Console.WriteLine(sortedList[i].ToString());
}
}
void Insert(List<KeyValuePair<int, MyClass>> sortedList, KeyValuePair<int, MyClass> newItem)
{
int newIndex = sortedList.BinarySearch(newItem, this);
if (newIndex < 0)
sortedList.Insert(~newIndex, newItem);
else
{
while (newIndex < sortedList.Count && (sortedList[newIndex].Key == newItem.Key))
newIndex++;
sortedList.Insert(newIndex, newItem);
}
}
#region IComparer<KeyValuePair<int,MyClass>> Members
public int Compare(KeyValuePair<int, MyClass> x, KeyValuePair<int, MyClass> y)
{
return x.Key.CompareTo(y.Key);
}
#endregion
}
Or you could have a sorted list of lists:
static void Main(string[] args)
{
SortedDictionary<int, List<MyClass>> sortedList = new SortedDictionary<int,List<MyClass>>();
foreach (KeyValuePair<int, MyClass> kv in new KeyValuePair<int, MyClass>[] {
new KeyValuePair<int, MyClass>(4, new MyClass("four")),
new KeyValuePair<int, MyClass>(7, new MyClass("seven")),
new KeyValuePair<int, MyClass>(5, new MyClass("five")),
new KeyValuePair<int, MyClass>(4, new MyClass("four-b")),
new KeyValuePair<int, MyClass>(4, new MyClass("four-c")),
new KeyValuePair<int, MyClass>(7, new MyClass("seven-b")) })
{
List<MyClass> bucket;
if (!sortedList.TryGetValue(kv.Key, out bucket))
sortedList[kv.Key] = bucket = new List<MyClass>();
bucket.Add(kv.Value);
}
foreach(KeyValuePair<int, List<MyClass>> kv in sortedList)
{
for (int i = 0; i < kv.Value.Count; i++ )
Console.WriteLine(kv.Value[i].ToString());
}
}
I'm not sure if you can use List initializers in .NET 2.0 like I did in the first example above, but I'm sure you know how to populate a list with data.
.NET doesn't have huge support for stable sorts (meaning that equivalent elements maintain their relative order when sorted). However, you can write your own stable-sorted-insert using List.BinarySearch and a custom IComparer<T> (that returns -1 if the key is less than or equal to the target, and +1 if greater).
Note that List.Sort is not a stable sort, so you'd either have to write your own stable quicksort routine or just use insertion sort to initially populate the collection.
did you contemplate the NameValueCollection class as it allows you to store multiple values per key? you could for example have the following:
NameValueCollection nvc = new NameValueCollection();
nvc.Add("1", "one");
nvc.Add("2", "two");
nvc.Add("3", "three");
nvc.Add("2", "another value for two");
nvc.Add("1", "one bis");
and then to retrieve the values you could have:
for (int i = 0; i < nvc.Count; i++)
{
if (nvc.GetValues(i).Length > 1)
{
for (int x = 0; x < nvc.GetValues(i).Length; x++)
{
Console.WriteLine("'{0}' = '{1}'", nvc.GetKey(i), nvc.GetValues(i).GetValue(x));
}
}
else
{
Console.WriteLine("'{0}' = '{1}'", nvc.GetKey(i), nvc.GetValues(i)[0]);
}
}
which give the output:
'1' = 'one'
'1' = 'one bis'
'2' = 'two'
'2' = 'another value for two'
'3' = 'three'
In .NET 2.0 you can write :
List<KeyValuePair<string, string>> keyValueList = new List<KeyValuePair<string, string>>();
// Simulate your list of key/value pair which key could be duplicate
keyValueList.Add(new KeyValuePair<string,string>("1","One"));
keyValueList.Add(new KeyValuePair<string,string>("2","Two"));
keyValueList.Add(new KeyValuePair<string,string>("3","Three"));
// Here an entry with duplicate key and new value
keyValueList.Add(new KeyValuePair<string, string>("2", "NEW TWO"));
// Your final sorted list with one unique key
SortedList<string, string> sortedList = new SortedList<string, string>();
foreach (KeyValuePair<string, string> s in keyValueList)
{
// Use the Indexer instead of Add method
sortedList[s.Key] = s.Value;
}
Output :
[1, One]
[2, NEW TWO]
[3, Three]
How about this
SortedList<string, List<string>> sl = new SortedList<string, List<string>>();
List<string> x = new List<string>();
x.Add("5");
x.Add("1");
x.Add("5");
// use this to load
foreach (string z in x)
{
if (!sl.TryGetValue(z, out x))
{
sl.Add(z, new List<string>());
}
sl[z].Add("F"+z);
}
// use this to print
foreach (string key in sl.Keys)
{
Console.Write("key=" + key + Environment.NewLine);
foreach (string item in sl[key])
{
Console.WriteLine(item);
}
}
I had a similar issue where I was designing a game similar to the concept of a Chess game where you have the computer make a move. I needed to have the possibility of multiple pieces being able to make a move and thus I needed to have multiple Board-States. Each BoardState needed to be ranked based on the position of the pieces. For argument sake and simplicity, say my game was Noughts and Crosses and I was Noughts and the Computer was Crosses. If the board-state was showing 3 in a row of Noughts then this is the best state for me, if it shows 3 in a row of Crosses then this is the worst state for me and best for the computer. There are other states during the game that are more favourible to one or the other and furthermore there are muliplte states that result in a Draw, so how do I go about ranking it when there are equal rank scores. This is what I came up with (apologise in advance if you are not a VB programmer).
My comparer class:
Class ByRankScoreComparer
Implements IComparer(Of BoardState)
Public Function Compare(ByVal bs1 As BoardState, ByVal bs2 As BoardState) As Integer Implements IComparer(Of BoardState).Compare
Dim result As Integer = bs2.RankScore.CompareTo(bs1.RankScore) 'DESCENDING order
If result = 0 Then
result = bs1.Index.CompareTo(bs2.Index)
End If
Return result
End Function
End Class
My declarations:
Dim boardStates As SortedSet(Of BoardState)(New ByRankScoreComparer)
My Board-State implementation:
Class BoardState
Private Shared BoardStateIndex As Integer = 0
Public ReadOnly Index As Integer
...
Public Sub New ()
BoardStateIndex += 1
Index = BoardStateIndex
End Sub
...
End Class
As you can see RankScores are maintained in descending order and any 2 states having the same rank-score the later state goes to the bottom as it will always have a greater assigned Index and thus this allows duplicates. I can also safely call boardStates.Remove(myCurrentBoardState) which also uses the comparer and the comparer must return a 0 value in order to locate the objected to be deleted.

Sort Dictionary<> on value, lookup index from key

I have a Dictionary<> which I want to sort based on value so I've done this by putting the dictionary into a List<> then using the .Sort method.
I've then added this back into a Dictionary<>. Is it possible to lookup the new index/order by using the Dictionary key??
Dictionary<int, MyObject> toCompare = new Dictionary<int, MyObject>();
toCompare.Add(0, new MyObject());
toCompare.Add(1, new MyObject());
toCompare.Add(2, new MyObject());
Dictionary<int, MyObject> items = new Dictionary<int, MyObject>();
List<KeyValuePair<int, MyObject>> values = new List<KeyValuePair<int, MyObject>> (toCompare);
// Sort.
values.Sort(new MyComparer());
// Convert back into a dictionary.
foreach(KeyValuePair<int, PropertyAppraisal> item in values)
{
// Add to collection.
items.Add(item.Key, item.Value);
}
// THIS IS THE PART I CAN'T DO...
int sortedIndex = items.GetItemIndexByKey(0);
Keep your data in the Dictionary<TKey,TValue>, but use a List<TKey> to sort the keys, then iterate as such:
IDictionary<int, MyObject> dict = new Dictionary<int, MyObject>();
// ... Populate dict with data.
IList<int> keyList = new List<int>();
keyList.AddRange(dict.Keys);
// Sort keyList based on key's value.
// MyObject must implement IComparable<MyObject>.
keyList.Sort(delegate(int x, int y) {
return dict[x].CompareTo(dict[y]);
});
foreach (int key in keyList) {
MyObject value = dict[key];
}
This way, your list is merely a sorted index and does not affect your storage algorithm.
Take this extension method:
public static Dictionary<TKey, TValue> Sort<TKey, TValue, TSortingKey>(this Dictionary<TKey, TValue> source,
Func<KeyValuePair<TKey, TValue>, TSortingKey> selector)
{
var result = new Dictionary<TKey, TValue>();
foreach (var pair in source.OrderBy(selector))
result.Add(pair.Key, pair.Value);
return result;
}
And usage:
Dictionary<int, MyType> source = new Dictionary<int, MyType>();
Dictionary<int, MyType> sortedDictionary = source.Sort(i => i.Value.Property1); //sort dictionary by values (by property "Property1" of type MyType
Hope this helps

Categories

Resources