get combination from a list of key-values - c#

I have a dict<string, list<string>>, say 3 keys in dict, the first key has 2 values, the secodn 3 values, the third key has 3 values. If I get a value from each value set, then I will have a combination of 2*3*3 = 18 sets
How to code in c#?
thanks
Edit
Sorry did not make it clear
I want something like this
say I have dict like this
{"1",new List<String>(){"a", "b"}},
{"2",new List<String>(){"c", "d", "e"}},
{"3", new List<string>() {"f", "g"}
I want output like this
acf, acg, adf, adg, aef, aeg
bcf, bcg, bdf, bdg, bef, beg

With Linq:
var dict = new Dictionary<String, List<String>>() {
{"1",new List<String>(){"a", "b"}},
{"2",new List<String>(){"c", "d", "e"}},
{"3",new List<String>(){"f", "g", "h"}},
};
var combis = from kv in dict
from val1 in kv.Value
from val2 in kv.Value
select string.Format("{0}{1}", val1, val2);
foreach (var combi in combis)
Console.WriteLine(combi);
demo: http://ideone.com/nm7mY

Quick & dirty but you may polish this method. The result list contains expected result:
Usage:
var dict = new Dictionary<String, List<String>>() {
{"1",new List<String>(){"a", "b"}},
{"2",new List<String>(){"c", "d", "e"}},
{"3",new List<String>(){"f", "g"}},
};
var collections = dict.Select(kvp => kvp.Value).ToArray();
var result = new List<string>();
GetNextProduct(collections, 0, String.Empty, result);
Method that produces the result:
private static void GetNextProduct(IEnumerable<string>[] collections, int collectionIndex, string currentProduct, IList<string> results)
{
var currentList = collections[collectionIndex];
bool isLast = collections.Length == collectionIndex + 1;
foreach (var s in currentList)
{
if (isLast) results.Add(currentProduct + s);
else GetNextProduct(collections, collectionIndex + 1, currentProduct + s, results);
}
}

I think you mean this?
Dictionary<string, int> dict = new Dictionary<string, int>
{
{ "Hello World", 1 },
{ "HelloWorld", 1 },
{ "Hello World", 1 },
};
foreach (var item in dict) // var is of type KeyValuePair<string, int>
Console.WriteLine(item.Key + ", " + item.Value);

Dictionary<string, List<int>> storage = new Dictionary<string, List<int>>();
storage.Add("key1", new List<int>() { 2, 7 });
storage.Add("key2", new List<int>() { 8, 4, 1});
storage.Add("key3", new List<int>() { 3, 9, 3 });
foreach (string key in storage.Keys)
{
//access to single storage...
List<int> subStorage = (List<int>)storage[key];
foreach (int item in subStorage)
{
//access to single value inside storage...
}
}

I would try something like the following if I was trying to read or edit the values in the lists:
Dictionary<int, List<string>> dict = new Dictionary<int, List<string>>();
var arrayOfValues = dict.Values.ToArray();
for (int i = 0; i < arrayOfValues.Length; i++)
{
for (int j = 0; j < arrayOfValues[i].Count; j++)
{
//read/edit arrayOfValues[i][j];
}
}
You do not need recursion since you know the dept of the "tree".

Related

How to get except between two Dictionaries<int, IEnumerable<string>>?

I have two Dictionaries>
var test1 = await GetTest1();
var test2 = await GetTest2();
var groupedTest1 = test1.GroupBy(j => j.someField1)
.ToDictionary(k => k.Key, d => d.Select(s => s.someField2));
var groupedTest2 = test2.GroupBy(a => a.someField1)
.ToDictionary(k => k.Key, d => d.Select(s => s.someField2));
And I need two get the difference between them.
For example:
var result = groupedTest1.Except(groupedTest2);
If groupedTest1 contains something IEnumerable which contains in groupedTest2 I don't need to include this. Besides, I need to include check only for a similar key. My question is:
How can I do it?
groupedTest1 : { { Key: 1, IEnumerable: "test1, test2" },
{ Key: 2, IEnumerable: "test3, test4" } } groupedTest2 : {
{ Key: 2, IEnumerable: "test3, test4" } }
result should be Key: 1, IEnumerable: "test1, test2"
If I understand it you effectively have 2 actions; first, get all the keys that don't match and their entire entry should be in the result, and second for matching keys only get the values that don't match. I've put together a little console app to display this:
static void Main(string[] args)
{
//2 test dictionaries. Key 1 and it's values should be displayed and Key 3 with only "test5".
var test1 = new Dictionary<int, IEnumerable<string>>
{
{ 1, new List<string>{ "test1", "test2" } },
{ 2, new List<string>{ "test3", "test4" } },
{ 3, new List<string>{ "test3", "test4", "test5" } }
};
var test2 = new Dictionary<int, IEnumerable<string>>
{
{ 2, new List<string>{ "test3", "test4" } },
{ 3, new List<string>{ "test3", "test4" } }
};
//get non-matching keys first.
Console.WriteLine("Non-matching keys:");
var entriesWithNoMatch = test1.Where(x => !test2.ContainsKey(x.Key));
foreach (var entry in entriesWithNoMatch)
{
WriteResults(entry.Key, entry.Value.ToList());
}
//get matching keys and compare values
Console.WriteLine("Matching keys, non-matching values:");
var matchingKeys = test1.Keys.Intersect(test2.Keys);
foreach (var match in matchingKeys)
{
var result = new KeyValuePair<int, IEnumerable<string>>(match, test1[match].Except(test2[match]));
if (result.Value.Count() > 0)
{
WriteResults(match, result.Value.ToList());
}
}
Console.ReadLine();
}
//simple method to loop through results displaying key and results.
static void WriteResults(int key, IList<string> results)
{
var sb = new StringBuilder();
foreach (var r in results)
{
sb.Append(r + ",");
}
if (sb.Length > 1)
{
sb.Remove(sb.Length - 1, 1);
}
Console.WriteLine("Key: " + key.ToString() + ", results: " + sb.ToString());
sb.Clear();
}
Results:

After removing an item from a Dictionary, how to change the other keys accordingly?

For example, a dictionary contains,
key: 1 2 3 4 5
value: a b c d e
Once you delete the item b, the dictionary would looks like this,
key: 1 3 4 5
value: a c d e
However, I want the key to be like so,
key: 1 2 3 4
value: a c d e
Is there any possible way to do this?
You want an Array or a List, not a dictionary.
If you want to keep it as a dictionary, you could convert it to a list, then remove the entry, then reconvert it back to a dictionary.
var list = new List<string>();
foreach(var item in dictionary)
{
list.Add(item.Value);
}
var newDict = new Dictionary<int, string>();
for(int i = 1; i < list.Count + 1; i++)
{
newDict.Add(i,list[i]);
}
Don't do this though.
As others have said, this is not the right approach. However, it is possible. Here's another way:
public static void Test()
{
var foo = new Dictionary<int, string> { { 1, "a" }, { 2, "b" }, { 3, "c" }, { 4, "d" }, { 5, "e" } };
RemoveItemByKey(ref foo, 3);
RemoveItemByValue(ref foo, "a");
foreach (var kvp in foo)
{
Console.WriteLine("{0}: {1}", kvp.Key, kvp.Value);
}
// Output:
// 1: b
// 2: d
// 3: e
}
public static void RemoveItemByValue(ref Dictionary<int, string> dictionary, string valueToRemove)
{
foreach (var kvp in dictionary.Where(item=>item.Value.Equals(valueToRemove)).ToList())
{
RemoveItemByKey(ref dictionary, kvp.Key);
}
}
public static void RemoveItemByKey(ref Dictionary<int, string> dictionary, int keyToRemove)
{
if (dictionary.ContainsKey(keyToRemove))
{
dictionary.Remove(keyToRemove);
int startIndex = 1;
dictionary = dictionary.ToDictionary(keyValuePair => startIndex++, keyValuePair => keyValuePair.Value);
}
}

Linq SelectMany project to index

I have 2 different collections.
pseudo code:
// index string by int : Dictionary<int, string>
index = { 0, "a" }, { 1, "b" }, { 2, "c" }
// data : Dictionary<string, List<Data>>
data = {"a", { "data00", "data01"..}},
{"b", {"data20", "data21", "data22"...}},
{"c", {"data4",...}}...
I want project int index to data string value and
var result = data.SelectMany ... new { IntIndex, DataValue }
I need to flatten lists into one sequence and pair the Data values with int index using string index.
I have slightly update types and values (your Dictionary contains duplicated keys and index wasn't specified) but it shouldn't be a problem. You may modify function easily for your data types.
var index = new List<Tuple<int, string>> {Tuple.Create(0, "a"), Tuple.Create(1, "b")};
var data = new Dictionary<string, IEnumerable<string>>()
{
{"a", new[] {"data00", "data01"}},
{"b", new[] {"data20", "data21", "data22"}},
{"c", new[] {"data4"}}
};
var result = index
.Join(data, x => x.Item2, y => y.Key, (x,y) => new KeyValuePair<int, IEnumerable<string>>(x.Item1, y.Value))
.SelectMany(x => x.Value, (x, y) => new KeyValuePair<int, string>(x.Key, y));
Assuming your duplication of keys was accidental, you could try this
Dictionary<int, List<Data>> intData = new Dictionary<int, List<Data>>();
foreach (var iVal in index)
{
List<Data> tmpList = new List<Data>();
if (data.TryGetValue(iVal.Value, out tmpList))
{
intData.Add(iVal.Key, tmpList);
}
}
If you can have duplicate keys then a dictionary is not the right structure.
var index = new List<Tuple<int, string>> {Tuple.Create(0, "a"), Tuple.Create(1, "b")};
var data = new Dictionary<string, IEnumerable<string>>()
{
{"a", new[] {"data00", "data01"}},
{"b", new[] {"data20", "data21", "data22"}},
{"c", new[] {"data4"}}
};
var res =
(from i in index
join d in data on i.Item2 equals d.Key
select new {Key = i.Item1, Value = d.Value})
.SelectMany(x => x.Value, (x, v) => new {x.Key, Value = v});

compare two arrays and show count of characters

I have two arrays:
string[] array1 = {"a","b","c","d","e"}
string[] array1 = {"x","y","a","b","a"}
I want to print the result like this:
a = 3
b = 2
c = 1
d = 1
e = 1
x = 1
y = 1
z = 1
I can run a loop inside the loop and find this out but is there a better way to achieve the same result?
I want to do this in plain C# without using LINQ.
You can use LINQ to accomplish this:
var counts = array1.Concat(array2)
.GroupBy(v => v)
.Select(g => new { Value=g.Key, Number=g.Count() });
foreach(var item in counts.OrderBy(i => i.Value))
Console.WriteLine("{0} = {1}", item.Value, item.Number);
Given that you want to avoid using LINQ and the extension methods for some reason, you could build your own dictionary:
var counts = new Dictionary<string, int>();
foreach(string item in array1)
{
if (counts.ContainsKey(item))
counts[item]++;
else
counts[item] = 1;
}
foreach(string item in array2)
{
if (counts.ContainsKey(item))
counts[item]++;
else
counts[item] = 1;
}
// Print out counts
foreach(var kvp in counts)
Console.WriteLine("{0} = {1}", kvp.Key, kvp.Value);
Note that this doesn't sort the results - if you need them sorted, you'd have to do that as well.
You can use Concat, GroupBy and OrderByDescending:
var both = array1.Concat(array2);
var groups = both.GroupBy(s => s).OrderByDescending(g => g.Count());
Console.Write(
String.Join(
Environment.NewLine,
groups.Select(g => String.Format("{0} = {1}", g.Key, g.Count()))));
This looks like a job for Linq:
var charCounts = array1.Concat(array2)
.GroupBy(c=>c)
.Select(g=>new Tuple<char, int>(g.Key, g.Count());
.OrderBy(t=>t.Item1);
foreach(var result in charCounts)
Console.WriteLine(String.Format("{0} = {1}", t.Item1, t.Item2));
Read through the two arrays and put them into one dictionary. Keys are the members in the array like "a", "b", etc. Values are integers as count. So, if a key, exists, you increment the count; otherwise put the key into dictionary with a value as 1.
Well, most naive implementation based on type of string would be something like this:
class Program
{
static void Main(string[] args)
{
string[] array1 = {"a", "b", "c", "d", "e"};
string[] array2 = {"x", "y", "a", "b", "a"};
var histogram = new Dictionary<string, int>();
Fill(histogram, array1);
Fill(histogram, array2);
foreach (var p in histogram)
{
Console.WriteLine("{0}={1}",p.Key,p.Value);
}
}
private static void Fill(Dictionary<string, int> histogram, string[] a)
{
foreach (string s in a)
{
if (histogram.ContainsKey(s))
histogram[s] += 1;
else
histogram[s] = 1;
}
}
}
which is build dynamic histogram, print.
another simple approach is like this, but it's of worse readability:
static void Main(string[] args)
{
string[] array1 = {"a", "b", "c", "d", "e"};
string[] array2 = {"x", "y", "a", "b", "a"};
string [] concat = new string[array1.Length+array2.Length];
Array.Copy(array1,concat,array1.Length);
Array.Copy(array2,0,concat,array1.Length,array2.Length);
Array.Sort(concat);
int pos = 0;
while(pos<concat.Length)
{
var cur = concat[pos];
int count = 0;
while ( (pos<concat.Length) && (concat[pos]==cur))
{
pos += 1;
count += 1;
}
Console.WriteLine("{0}={1}",cur,count);
}
}
generally - concat, sort, histogram on sorted data.

C# comparing collections

I'm new to C# and need some help with comparing collections. I have two List<string>
collections with their contents as below:
Collection Old:
{"AAA","BBB","CCC"}
Collection New:
{"BBB","CCC","DDD"}
I want to get a collection like below:
Collection Final:
{"AAA", "Remove"; "BBB", "Keep"; "CCC", "Keep"; "DDD", "Add"}
How can I do this?
old.Except(new) will give you those items to remove
new.Except(old) will give you items to add
old.Intersect(new) will give you items to keep
(This is assuming you don't mind using the System.Linq namespace)
Or if you prefer, you can consider each item individually and check the existence in each list
var oldList = new List<String>() {"AAA", "BBB", "CCC"};
var newList = new List<String>() {"BBB", "CCC", "DDD"};
var diffDictionary = new Dictionary<string, string>();
foreach (var oldEntry in oldList)
{
diffDictionary.Add(oldEntry, "Remove");
}
foreach (var newEntry in newList)
{
if (diffDictionary.ContainsKey(newEntry))
{
diffDictionary[newEntry] = "Keep";
}
else
{
diffDictionary.Add(newEntry, "Add");
}
}
foreach (var dDico in diffDictionary)
{
Console.WriteLine(string.Concat("Key: ", dDico.Key, " Value: ", dDico.Value));
}
You can use a dictionary to do this...
at the end, each element in the dictionary will tell you how many items of each kind were removed or added.
It will indicate this with a count, not a simple 3 state flag... that is because you may have added or removed repeated items... what if you insert 3 AAA's in the second collection.
string[] col1 = new string[] { "AAA", "BBB", "CCC" };
string[] col2 = new string[] { "BBB", "CCC", "DDD" };
Dictionary<string, int> colDic = new Dictionary<string, int>();
foreach (var item in col1)
{
int num;
if (colDic.TryGetValue(item, out num))
colDic[item] = num - 1;
else
colDic[item] = -1;
}
foreach (var item in col2)
{
int num;
if (colDic.TryGetValue(item, out num))
colDic[item] = num + 1;
else
colDic[item] = 1;
}
The end result will look like this:
AAA = -1
BBB = 0
CCC = 0
DDD = 1
In 1 line (sort of)!
string[] colOld = {"AAA","BBB","CCC"};
string[] colNew = {"BBB","CCC","DDD"};
dynamic colALL = (from o in colOld.Union(colNew)
select new {Value = o, Action =
colOld.Any(s => s == o) ?
colNew.Any(s => s == o) ? "Keep" : "Remove"
: "Add"
}).ToList();
Note: This is a developer fusion conversionof the below vb.net which does work - I've not had chance to test the c# version:
Dim colOld() As String = {"AAA", "BBB", "CCC"}
Dim colNew() As String = {"BBB", "CCC", "DDD"}
Dim colALL = (From o As String In colOld.Union(colNew) _
Select New With {.Value = o, .Action = _
If(colOld.Any(Function(s) s = o), _
If(colNew.Any(Function(s) s = o), "Keep", "Remove"), _
"Add")}).ToList
If you have this method
public static IEnumerable<T> Concat<T>(params IEnumerable<T>[] sequences)
{
return sequences.SelectMany(x => x);
}
you should be able to write:
static readonly string Remove = "Remove";
static readonly string Keep = "Keep";
static readonly string Add = "Add";
var result = Concat
(
old.Except(new).Select(x => new { x, Remove }),
old.Intersect(new).Select(x => new { x, Keep }),
new.Except(old).Select(x => new { x, Add })
);
Of course you can use the built-in Enumerable.Concat method but I find mine more elegant.

Categories