I have 6 dictionaries. I want to compare another dictionaries against each one of them and see what dictionaries contains what strings. Is it possible to do with a foreach loop?
static Dictionary<string, int> d = new Dictionary<string, int>();
static Dictionary<string, double> dNL = new Dictionary<string, double>();
static Dictionary<string, double> dDE = new Dictionary<string, double>();
static Dictionary<string, double> dFR = new Dictionary<string, double>();
static Dictionary<string, double> dSP = new Dictionary<string, double>();
static Dictionary<string, double> dEN = new Dictionary<string, double>();
static Dictionary<string, double> dIT = new Dictionary<string, double>();
foreach (var f in d)
{
if (dNL.ContainsKey(f.Key))
{
//add to a numeric?
}
if (dDE.ContainsKey(f.Key))
{
//add to a numeric?
}
}
something like this?
what I currently have (and not working like intended):
// need to find a better solution
foreach (var f in d)
{
if (dNL.ContainsKey(f.Key))
{
dNLtotaal++;
}
}
foreach (var f in d)
{
if (dDE.ContainsKey(f.Key))
{
dDEtotaal++;
}
}
foreach (var f in d)
{
if (dFR.ContainsKey(f.Key))
{
dFRtotaal++;
}
}
foreach (var f in d)
{
if (dSP.ContainsKey(f.Key))
{
dSPtotaal++;
}
}
foreach (var f in d)
{
if (dEN.ContainsKey(f.Key))
{
dENtotaal++;
}
}
foreach (var f in d)
{
if (dIT.ContainsKey(f.Key))
{
dITtotaal++;
}
}
// NEED A MUCH BETTER SOLUTION
List<int> totaleD = new List<int>();
totaleD.Add(dNLtotaal);
totaleD.Add(dDEtotaal);
totaleD.Add(dFRtotaal);
totaleD.Add(dSPtotaal);
totaleD.Add(dENtotaal);
totaleD.Add(dITtotaal);
int max = !totaleD.Any() ? -1 : totaleD.Select((value, index) => new { Value = value, Index = index }).Aggregate((a, b) => (a.Value > b.Value) ? a : b).Index;
var maxIndex = totaleD.IndexOf(totaleD.Max());
Console.WriteLine(maxIndex);
You can do something like this:
var items = d.Keys;
var dictionaries = new[] { dNL, dDE, dFR, dSP, dEN, dIT };
var result = dictionaries.Select((d, index) =>
new {
Index = index,
Matches = items.Count(i => d.ContainsKey(i))
})
.OrderByDescending(i => i.Matches)
.Select(i => i.Index)
.FirstOrDefault();
Which gives you the index of the dictionary with the most matches
You could use lambda expressions to get the desired results. In following example, I tried to use two dictionaries:
int dNLtotaal = 0;
Dictionary<string, double> dNL = new Dictionary<string, double>();
Dictionary<string, double> dDE = new Dictionary<string, double>();
dNL.Keys.Where(k => dDE.ContainsKey(k)).ToList().ForEach(k => dNLtotaal++);
Hope it helps
Why not to have 1 Dictionary instead of 6? And keep there a pair [string, List[SomeObject]] where SomeObject is a class like
class SomeObject
{
public Enum Type;//dNL, dDE etc
public double Value;
}
Related
I'm trying to build this datastructure with a nested dictionary:
["A",["A",123]],
["B",["B",123]],
["C",["C",123]],
And then loop over the data structure and print out the values.
The first problem is, that all the nested dictionaries are the same {"C",123}.
I think it's because it is the same object, but I don't know how to overcome that. Can I dynamically create new objects in the loop ?
The other problem i face is in the loop where I try to print out the Values.
The compiler says that it can't convert Dictionary to Dictionary.
using System;
using System.Collections.Generic;
namespace ConsoleApp1
{
class Program
{
public static void Main()
{
List<string> liste = new() { "A", "B", "C" };
Dictionary<string, Dictionary<string, int>> DictOfDicts = new();
Dictionary<string, int> DictOfData = new();
foreach (string i in liste)
{
DictOfData.Clear();
DictOfData.Add(i, 123);
DictOfDicts.Add(i, DictOfData);
}
foreach (Dictionary<string, int> i in DictOfDicts)
{
Console.WriteLine("Some result");
}
}
}
}
You declared DictOfData outside of the foreach loop. Then, all the operations inside the loop are done on the same object. So, you are clearing and filling the same dictionary object over and over again, on each loop iteration.
Just move you declaration of DictOfData to inside the loop, and you'll be good to go.
Bonus:
The whole operation you displayed in the questions can be done with just this:
liste.ToDictionary(x => x, x => new Dictionary<string, int>() { { x, 123 } })
var liste = new List<string>() { "A", "B", "C" };
var DictOfDicts = new Dictionary<string, Dictionary<string, int>>();
foreach (var i in liste)
{
// Create here a new DictOfData to add it to DicOfCicts.
var DictOfData = new Dictionary<string, int>();
DictOfData.Add(i, 123);
DictOfDicts.Add(i, DictOfData);
}
The structure of DicOfDicts is,
["A",["A",123]],
["B",["B",123]],
["C",["C",123]],
I've used a slightly older C# language specification for the answer, and made the type declarations more clear for you to understand.
List<string> list = new List<string>() { "A", "B", "C" };
Dictionary<string, Dictionary<string, int>> parent = new Dictionary<string, Dictionary<string, int>>();
foreach (string i in list)
{
Dictionary<string, int> child = new Dictionary<string, int>();
child.Add(i, 123);
parent.Add(i, child);
}
foreach (KeyValuePair<string, Dictionary<string, int>> parentPair in parent)
{
Dictionary<string, int> childDictionary = parentPair.Value;
foreach (var childPair in childDictionary)
{
Console.WriteLine(childPair.Value);
}
}
It's a very easy exercise to fix your code. Simply replace the DictOfData.Clear(); with the declaration of DictOfData itself. In other words, move the line Dictionary<string, int> DictOfData = new(); into the loop. That way you have a fresh instance of the nested dictionary rather than reusing the old one.
Try this code:
List<string> liste = new() { "A", "B", "C" };
Dictionary<string, Dictionary<string, int>> DictOfDicts = new();
foreach (string i in liste)
{
Dictionary<string, int> DictOfData = new();
DictOfData.Add(i, 123);
DictOfDicts.Add(i, DictOfData);
}
foreach (KeyValuePair<string, Dictionary<string, int>> i in DictOfDicts)
{
Console.WriteLine($"[{i.Key},{String.Join(",", i.Value.Select(x => $"[{x.Key},{x.Value}]"))}]");
}
I have this transitionMap: Dictionary<Dictionary<int, char>, int> transitionMap;
And I also have this dictionary: Dictionary<int, char> dictionary = new Dictionary<int, char> {{0, 'a'}};.
How do I get the value inside transitionMap that corresponds to dictionary1.
This is what I've tried:
Dictionary<int, char> dictionary = new Dictionary<int, char> {{stateNum, symbol}};
if (this.transitionMap.ContainsKey(dictionary))
{
int nextState = this.transitionMap[dictionary];
Console.WriteLine("nextstate {0}", nextState);
}
If you want to compare two dictionaries for equality then having a "super dictionary" will not help you in any way. You will have to manually compare all elements in two dictionaries.
First, compare the number of elements. Then run a loop through one dictionary, and with the key find the value in second dictionary, and if exists compare two values.
Solution with Linq :
class Program
{
static void Main(string[] args)
{
var transitionMap = new Dictionary<Dictionary<int, char>, int>();
var dictionary = new Dictionary<int, char> { { stateNum, symbol } };
...
var found = transitionMap.Keys.FirstOrDefault(d => Equal(d, dictionary));
if(found == null)
{
int nextState = transitionMap[found];
Console.WriteLine("nextstate {0}", nextState);
}
}
static bool Equal(Dictionary<int, char> a, Dictionary<int, char> b)
{
return a.Count == b.Count && a.All(akv => b.TryGetValue(akv.Key, out char bval) && akv.Value == bval);
}
}
I Have one Dictionary
Dictionary<string, string> rList = new Dictionary<string, string>();
rList .Add("/a/b/c", "35");
rList .Add("/a/c/f/v", "25");
rList .Add("/a/r/d/c/r/v", "29");
rList .Add("/a", "21");
rList .Add("/a/f, "84");
I just want to sort this Dictionary based on the number of number of '/' present in the key. my expected out put is ,
("/a/r/d/c/r/v", "29")
("/a/c/f/v", "25")
("/a/b/c", "35")
("/a/f, "84")
("/a", "21")
The Dictionary<TKey, TValue> type is an unordered collection in .Net. If you want ordering then you need to use SortedDictionary<TKey, TValue> instead and provide a custom IComparer<string> which counts the / values in the string.
sealed class SlashComparer : IComparer<string> {
static int CountSlashes(string str) {
if (String.IsNullOrEmpty(str)) {
return 0;
}
int count = 0;
for (int i = 0; i < str.Length; i++) {
if (str[i] == '/') {
count++;
}
}
return count;
}
public int Compare(string left, string right) {
int leftCount = CountSlashes(left);
int rightCount = CountSlashes(right);
return rightCount - leftCount;
}
}
To use with a SortedDictionary the only thing you need to change is the declaration
var comparer = new SlashComparer();
var rList = new SortedDictionary<string, string>(comparer);
The rest of the code can remain the same
As JaredPar answered already Dictionary<TKey, TValue> content has no order specified. However, you can get List<KeyValuePair<TKey, TValue>> with desired order:
List<KeyValuePair<string, string>> results = rList.OrderByDescending(x => x.Key.Count(c => c == '/')).ToList();
Try this:
var result = rList.OrderBy(input => input.Key.Select(c => c == '/').Count()).Reverse().ToList();
from linqpad:
void Main()
{
Dictionary<string, string> rList = new Dictionary<string, string>();
rList .Add("/a/b/c", "35");
rList .Add("/a/c/f/v", "25");
rList .Add("/a/r/d/c/r/v", "29");
rList .Add("/a", "21");
rList .Add("/a/f", "84");
var x = from a in rList
let i = a.Key.ToCharArray().Count (k => k.Equals('/') )
orderby i descending
select a;
x.Dump();
}
GROUP["10"]["MATH"] = 30;
GROUP["11"]["MATH"] = 40;
GROUP["9"]["CHEM"] = 50;
...
Can u tell me how to use it with dictionaries. How to define a dictionary for this example?
Dictionary<string,Dictionary<string,int>>
The first [] returns a dictionary, and the second [] operates on that dictionary and returns an int
Dictionary<string, Dictionary<string, int>>
Use:
Dictionary<string, Dictionary<string, int>> dic = new Dictionary<string, Dictionary<string, int>>();
Dictionary<string, int> inner = new Dictionary<string, int>();
inner.Add("MATH", 30);
dic.Add("10", inner);
...
Access
dic["10"]["MATH"]
use this one ......
Dictionary<string,Dictionary<string,int>>
pls go through this link for more info ....On dictionaries,if you are new to dictionaries..
http://msdn.microsoft.com/en-us/library/xfhwa508.aspx
You could create a Dictionary<Tuple<string, string>, int> but you may better defining a class/ custom collection to better represent this, it depends on what your use case is.
An example of Dictionary<Tuple<string, string>, int>
var dict = new Dictionary<Tuple<string, string>, int>
{
{ new Tuple<string,string>("10", "MATH"), 30 },
{ new Tuple<string,string>("11", "MATH"), 40 },
{ new Tuple<string,string>("9", "CHEM"), 50 }
};
Option 1: Use a Dictionary<string, Dictionary<string, int>>.
Dictionary<string, int> group10 = new Dictionary<string, int>();
group10.Add("MATH", 30);
Dictionary<string, int> group11 = new Dictionary<string, int>();
group10.Add("MATH", 40);
Dictionary<string, int> group9 = new Dictionary<string, int>();
group10.Add("CHEM", 50);
var group = new Dictionary<string, Dictionary<string, int>>();
group.Add("10", group10);
group.Add("11", group11);
group.Add("9", group9);
int v1 = group["10"]["MATH"]; // v1 = 30
int v2 = group["11"]["MATH"]; // v2 = 40
int v3 = group["9"]["CHEM"]; // v3 = 50
Option 2: Or create a compound key for the dictionary that overrides GetHashCode and Equals, or you could use Tuple.
var group = new Dictionary<Tuple<string, string>, int>();
group.Add(Tuple.Create("10", "MATH"), 30);
group.Add(Tuple.Create("11", "MATH"), 40);
group.Add(Tuple.Create("9", "CHEM"), 50);
int v1 = group[Tuple.Create("10", "MATH")]; // v1 = 30
int v2 = group[Tuple.Create("11", "MATH")]; // v2 = 40
int v3 = group[Tuple.Create("9", "CHEM")]; // v3 = 50
If using Option 1 you must remember to create the second level Dictionary<string, int>, before adding the integer values.
Something like this may be
Dictionary<string, Dictionary<string><int>> dict = new Dictionary<string, Dictionary<string><int>>();
You could also create your own dictionary:
public class GroupDict
{
const string Separator = ";";
Dictionary<string, int> _internalDict = new Dictionary<string, int>();
public void Add(string key1, string key2, int value)
{
_internalDict.Add(key1 + Separator + key2, value);
}
public int this[string key1, string key2]
{
get { return _internalDict[key1 + Separator + key2]; }
set { _internalDict[key1 + Separator + key2] = value; }
}
public int Count
{
get { return _internalDict.Count; }
}
}
You can then use it like:
GroupDict groups = new GroupDict();
groups.Add("10", "MATH", 30);
// OR
groups["10", "MATH"] = 30;
Console.WriteLine(groups["10", "MATH"]);
Also note that you can't create a Multi-Key Dictionary in C#.
You will need your own struct for that.
How can I create a dictionary with no duplicate values from a dictionary that may have duplicate values?
IDictionary<string, string> myDict = new Dictionary<string, string>();
myDict.Add("1", "blue");
myDict.Add("2", "blue");
myDict.Add("3", "red");
myDict.Add("4", "green");
uniqueValueDict = myDict.???
Edit:
-I don't care which key is kept.
- Is there something using Distinct() operation?
What do you want to do with the duplicates? If you don't mind which key you lose, just build another dictionary like this:
IDictionary<string, string> myDict = new Dictionary<string, string>();
myDict.Add("1", "blue");
myDict.Add("2", "blue");
myDict.Add("3", "red");
myDict.Add("4", "green");
HashSet<string> knownValues = new HashSet<string>();
Dictionary<string, string> uniqueValues = new Dictionary<string, string>();
foreach (var pair in myDict)
{
if (knownValues.Add(pair.Value))
{
uniqueValues.Add(pair.Key, pair.Value);
}
}
That assumes you're using .NET 3.5, admittedly. Let me know if you need a .NET 2.0 solution.
Here's a LINQ-based solution which I find pleasantly compact...
var uniqueValues = myDict.GroupBy(pair => pair.Value)
.Select(group => group.First())
.ToDictionary(pair => pair.Key, pair => pair.Value);
The brute-force solution would be something like the following
var result = dictionary
.GroupBy(kvp => kvp.Value)
.ToDictionary(grp => grp.First().Value, grp.Key)
assuming you don't really care about the key used to represent a group of duplicates and it is acceptable to rebuild the dictionary.
Jon beat me to the .NET 3.5 solution, but this should work if you need a .NET 2.0 solution:
List<string> vals = new List<string>();
Dictionary<string, string> newDict = new Dictionary<string, string>();
foreach (KeyValuePair<string, string> item in myDict)
{
if (!vals.Contains(item.Value))
{
newDict.Add(item.Key, item.Value);
vals.Add(item.Value);
}
}
foreach (var key in mydict.Keys)
tempdict[mydict[key]] = key;
foreach (var value in tempdict.Keys)
uniquedict[tempdict[value]] = value;
Dictionary<string, string> test = new Dictionary<string,string>();
test.Add("1", "blue");
test.Add("2", "blue");
test.Add("3", "green");
test.Add("4", "red");
Dictionary<string, string> test2 = new Dictionary<string, string>();
foreach (KeyValuePair<string, string> entry in test)
{
if (!test2.ContainsValue(entry.Value))
test2.Add(entry.Key, entry.Value);
}
This is how I did it:
dictionary.add(control, "string1");
dictionary.add(control, "string1");
dictionary.add(control, "string2");
int x = 0;
for (int i = 0; i < dictionary.Count; i++)
{
if (dictionary.ElementAt(i).Value == valu)
{
x++;
}
if (x > 1)
{
dictionary.Remove(control);
}
}
In addition to the answer of Jon Skeet , if your value is an intern object you can use :
var uniqueValues = myDict.GroupBy(pair => pair.Value.Property)
.Select(group => group.First())
.ToDictionary(pair => pair.Key, pair => pair.Value);
This way you will remove the duplicate only on one property of the object
Just a footnote to those using the Revit API, this is one method that works for me in removing duplicate elements, when you can't use say wallType as your object type and instead need to leverage raw elements. it's a beaut mate.
//Add Pair.value to known values HashSet
HashSet<string> knownValues = new HashSet<string>();
Dictionary<Wall, string> uniqueValues = new Dictionary<Wall, string>();
foreach (var pair in wall_Dict)
{
if (knownValues.Add(pair.Value))
{
uniqueValues.Add(pair.Key, pair.Value);
}
}