Dictionary as key of another Dictionary / count number of equal Dictionarys - c#

I want to use a Dictionary as the key of another Dictionary, but the comparision for equal keys shall not use the reference for comparision, but the Dictionary's content. How can I do this?
Here is what I currently have: I want to know how many equal histograms (implemented as Dictionary) I have. For that I create another Dictionary numberOfHistogramOccurences with the histograms as key, the value shall then be increased by one on each new addition of a histogram with equal content.
I am also open for hints on other ways of counting content-equal histograms/Dictionaries.
// define two histograms with equal content
Dictionary<int, int>[] histograms = new Dictionary<int, int>[2];
histograms[0] = new Dictionary<int, int>();
histograms[0][0] = 3;
histograms[0][5] = 1;
histograms[0][10] = 8;
histograms[1] = new Dictionary<int, int>();
histograms[1][0] = 3;
histograms[1][5] = 1;
histograms[1][10] = 8;
// use the equal histograms as key.
// as they are reference types, their reference is compared and not their content ):
var numberOfHistogramOccurences = new Dictionary<Dictionary<int, int>, int>();
foreach (var histogram in histograms)
{
if (!numberOfHistogramOccurences.ContainsKey(histogram))
numberOfHistogramOccurences[histogram] = 0;
numberOfHistogramOccurences[histogram]++;
}
// this gives two different keys;
// I need one key with a value of 2,
// as both histograms are equal
Debug.WriteLine("Number of different keys in numberOfHistogramOccurences: " + numberOfHistogramOccurences.Keys.Count);

Following my comment, using a custom comparer. Note that I added another histogram in order to check that it sees differences as well.
public static void Main()
{
// define two histograms with equal content
Dictionary<int, int>[] histograms = new Dictionary<int, int>[2];
histograms[0] = new Dictionary<int, int>();
histograms[0][0] = 3;
histograms[0][5] = 1;
histograms[0][10] = 8;
histograms[1] = new Dictionary<int, int>();
histograms[1][0] = 3;
histograms[1][5] = 1;
histograms[1][10] = 8;
histograms[2] = new Dictionary<int, int>();
histograms[2][0] = 1;
histograms[2][5] = 3;
histograms[2][10] = 8;
// use the equal histograms as key.
// as they are reference types, their reference is compared and not their content ):
/* change this line */
var numberOfHistogramOccurences = new Dictionary<Dictionary<int, int>, int>(new HistogramComparer());
/* ---------------- */
foreach (var histogram in histograms)
{
if (!numberOfHistogramOccurences.ContainsKey(histogram))
numberOfHistogramOccurences[histogram] = 0;
numberOfHistogramOccurences[histogram]++;
}
// this gives two different keys;
// I need one key with a value of 2,
// as both histograms are equal
Debug.WriteLine("Number of different keys in numberOfHistogramOccurences: " + numberOfHistogramOccurences.Keys.Count);
}
And the custom comparer class HistogramComparer:
public class HistogramComparer : IEqualityComparer<Dictionary<int, int>>
{
public bool Equals(Dictionary<int, int> x, Dictionary<int, int> y)
{
// check that y contains all x.Keys
foreach (var key in x.Keys)
if (!y.Keys.Contains(key))
return false;
// check that x contains all y.Keys
foreach (var key in y.Keys)
if (!x.Keys.Contains(key))
return false;
// check that keys have same values
foreach (var entry in x)
if (y[entry.Key] != entry.Value)
return false;
return true;
}
public int GetHashCode(Dictionary<int, int> obj)
{
int hash = 0;
foreach (var entry in obj)
hash ^= (entry.Key ^ entry.Value);
return hash;
}
}

Related

Dictionary to return a character list with their indices

I've been tasked with taking a string and returning a dictionary that has a map of characters to a list of their indices in a given string. The output should show which characters occur where in the given string.
This code passes the test:
public class CharacterIndexDictionary
{
public static Dictionary<string, List<int>> ConcordanceForString(string input)
{
var result = new Dictionary<string, List<int>>();
for (var index = 0; index < input.Length; index++)
{
// Get the character positioned at the current index.
// We could just use input[index] everywhere, but
// this is a little easier to read.
string currentCharacter = input[index].ToString();
// If the dictionary doesn't already have an entry
// for the current character, add one.
if (!result.ContainsKey(currentCharacter))
{
result.Add(currentCharacter, new List<int>());
}
// Add the current index to the list for
// the current character.
result[currentCharacter].Add(index);
}
return result;
}
}
If I wanted to index characters I'd use a Dictionary<char, List<int>> instead of using a string as the key, but this uses string because the test requires it.
This code block is like your code and in a way that you can understand
public Dictionary<string, List<int>> ConcordanceForString(string s)
{
Dictionary<string, List<int>> newDictionary = new Dictionary<string, List<int>>();
List<char> charList = new List<char>();
foreach (var item in s)
{
if (!charList.Any(x => x == item))
{
charList.Add(item);
List<int> itemInds = new List<int>();
for (int i = 0; i< s.Length; i++)
{
if (s[i] == item)
{
itemInds.Add(i);
}
}
newDictionary.Add(item.ToString(), itemInds);
}
}
return newDictionary;
}

dictionary default values as parameter

I initialize a dictionary with n keys and zero values. By parameter I can setup some values.
When calling the constructor I execute this
public Store(Dictionary<int, int> initialItems = null)
{
items = new Dictionary<int, int>();
for (int i = 0; i < 45; i++) // 45 items should exist
{
int initialAmount = 0; // 0 as starting value
if (initialItems != null) // parameter is passed in?
{
initialItems.TryGetValue(i, out initialAmount); // start with a higher value than 0
}
items.Add(i, initialAmount); // initialize value with 0 or more
}
}
private Dictionary<int, int> items;
I'm asking if this is a good way of passing starting values by parameter. I just want to create a bunch of items and set the value to 0 or a higher value if specified somewhere else, as a constructor parameter for example.
You can also pass initial dictionary to dictionary's constructor like this:
public Store(Dictionary<int, int> initialItems = null)
{
if (initialItems!=null)
items = new Dictionary<int, int>(initialItems);
else
items = new Dictionary<int, int>();
for (int i = 0; i < 45; i++) // 45 items should exist
{
if (!items.ContainsKey(i))
items.Add(i, 0); // initialize value with 0
}
}
private Dictionary<int, int> items;

Remove All Indexes in String

I have dictionary of int (Dictionary<int, int>) which has index of all parenthesis in a string (key was openStartParenthesisIndex and value was closeEndParenthesisIndex)
e.g in text
stringX.stringY(())() -> stringX.stringY$($()^)^$()^
$ = openParenthesisStartIndex
^ = closeParenthesisEndIndex
Dictionary items:
key value
(openParenthesisStartIndex) --- (closeParenthesisEndIndex)
item1 15 19
item2 16 18
item3 19 21
My problem was when I loop my dictionary and try to remove it on string, next loop the index was not valid since its already change because I remove it .
string myText = "stringX.stringY(())()";
Dictionary<int, int> myIndexs = new Dictionary<int, int>();
foreach (var x in myIndexs)
{
myText = myText.Remove(item.Key, 1).Remove(item.Value-1);
}
Question: how can i remove all index in a string (from startIndex[key] to endIndex[value])?
To prevent the index from changing, one trick is to remove the occurences starting from the end:
string myText = stringX.stringY(())();
Dictionary<int, int> myIndexs = new Dictionary<int, int>();
var allIndexes = myIndexs.Keys.Concat(myIndexs.Values);
foreach (var index in allIndexes.OrderByDescending(i => i))
{
myText = myText.Remove(index, 1);
}
Note that you probably don't need a dictionary at all. Consider replacing it by a list.
StringBuilder will be more suited to your case as you are continuously changing data. StringBuilder MSDN
Ordering the keys by descending order will work as well for removing all indexes.
Another workaround could be to place an intermediary character at required index and replace all instances of that character in the end.
StringBuilder ab = new StringBuilder("ab(cd)");
ab.Remove(2, 1);
ab.Insert(2, "`");
ab.Remove(5, 1);
ab.Insert(5, "`");
ab.Replace("`", "");
System.Console.Write(ab);
Strings when you make a change to a string a new string is always created, so what you want is to create a new string without the removed parts. This code is a little bit complicated because of how it deals with the potential overlap. Maybe the better way would be to cleanup the indexes, making a list of indexes that represent the same removals in the right order without overlap.
public static string removeAtIndexes(string source)
{
var indexes = new Tuple<int, int>[]
{
new Tuple<int, int>(15, 19),
new Tuple<int, int>(16, 18),
new Tuple<int, int>(19, 21)
};
var sb = new StringBuilder();
var last = 0;
bool copying = true;
for (var i = 0; i < source.Length; i++)
{
var end = false;
foreach (var index in indexes)
{
if (copying)
{
if (index.Item1 <= i)
{
copying = false;
break;
}
}
else
{
if (index.Item2 < i)
{
end = true;
}
}
}
if (false == copying && end)
{
copying = true;
}
if(copying)
{
sb.Append(source[i]);
}
}
return sb.ToString();
}

An integer array as a key for Dictionary

I wish to have the dictionary which uses an array of integers as keys, and if the integer array has the same value (even different object instance), they will be treated as the same key. How should I do it?
The following code does not work as b is different object instances.
int[] a = new int[] { 1, 2, 3 };
int[] b = new int[] { 1, 2, 3 };
Dictionary<int[], string> dic = new Dictionary<int[], string>();
dic.Add(a, "haha");
string output = dic[b];
You can create an IEqualityComparer to define how the dictionary should compare items. If the ordering of items is relevant, then something like this should work:
public class MyEqualityComparer : IEqualityComparer<int[]>
{
public bool Equals(int[] x, int[] y)
{
if (x.Length != y.Length)
{
return false;
}
for (int i = 0; i < x.Length; i++)
{
if (x[i] != y[i])
{
return false;
}
}
return true;
}
public int GetHashCode(int[] obj)
{
int result = 17;
for (int i = 0; i < obj.Length; i++)
{
unchecked
{
result = result * 23 + obj[i];
}
}
return result;
}
}
Then pass it in as you create the dictionary:
Dictionary<int[], string> dic
= new Dictionary<int[], string>(new MyEqualityComparer());
Note: calculation of hash code obtained here:
What is the best algorithm for an overridden System.Object.GetHashCode?
Maybe you should consider using a Tuple
var myDictionary = new Dictionary<Tuple<int,int>, string>();
myDictionary.Add(new Tuple<int,int>(3, 3), "haha1");
myDictionary.Add(new Tuple<int,int>(5, 5), "haha2");
According to MSDN , Tuple objects Equals method will use the values of the two Tuple objects
The easiest way if you don't care about actual hashing may just be to convert the array into a string. Adding a space to avoid numbers joining.
dic.Add(String.Join(" ",a), "haha");

C# dictionary adding to wrong key/value pair

I have the following foreach loop in my program:
Dictionary<string, int[]> summaryDate_clipsEpisodesImps = new Dictionary<string, int[]>();
Dictionary<string, int[]> summaryPartner_clipsEpisodesImps = new Dictionary<string, int[]>();
foreach (DataRow row1 in dt10.Rows)
{
int[] numbers = new int[3];
numbers[0] = 0;
numbers[1] = 0;
numbers[2] = 0;
if (!dictionary1.ContainsKey(row1["value1"].ToString().Trim()))
{
dictionary1.Add(row1["value1"].ToString().Trim(), numbers);
}
if (!dictionary2.ContainsKey(row1["value2"].ToString().Trim()))
{
dictionary2.Add(row1["value2"].ToString().Trim(), numbers);
}
if (row1["yes_or_no"].ToString().Trim() == "yes")
{
dictionary1[row1["value1"].ToString().Trim()][0] = dictionary1[row1["value1"].ToString().Trim()][0] + Convert.ToInt32(row1["a_number"]);
dictionary2[row1["value2"].ToString().Trim()][0] = dictionary2[row1["value2"].ToString().Trim()][0] + Convert.ToInt32(row1["a_number"]);
}
}
Essentially, I am looping through a datatable and creating a dictionary of string/int arrays based on values that I find in each record. Then I'm trying to increment the first value in the array based on the presence of another field in the record.
My problem occurs in the if statement when I check for the yes_or_no value. When the second line incrementing dictionary2 is present in this statement, the value in dictionary 1 is incremented by the same value. I have no idea why this is the case.
Please let me know if this isn't entirely clear. Thanks in advance for the help.
This is because the values in both dictionary entries point to the same instance of numbers. This means any change to one will affect the other.
To put a new instance in each dictionary you could do something similar to:
...
if (!dictionary1.ContainsKey(row1["value1"].ToString().Trim()))
{
dictionary1.Add(row1["value1"].ToString().Trim(), GetNumbersArray());
}
if (!dictionary2.ContainsKey(row1["value2"].ToString().Trim()))
{
dictionary2.Add(row1["value2"].ToString().Trim(), GetNumbersArray());
}
...
private int[] GetNumbersArray()
{
int[] numbers = new int[3];
numbers[0] = 0;
numbers[1] = 0;
numbers[2] = 0;
return numbers;
}
You're adding a pointer to the array to each dictionary. Both dictionaries look at the same array, so when you modify the array through dictionary2, dictionary1 sees the changes.

Categories

Resources