adding items to a list in a dictionary - c#

I'm trying to put values into a dictionary dependent on the key... For example, if in a list of keys at the index 0 there is a letter "a". I want to add the val with index 0 to a list inside of a dictionary with the key "a" ( dictionary (key is "a" at index 0 , val at index 0) ... dictionary (key is "b" at index 2 , val at index 2))
I'm expecting an output like this:
in listview lv1: 1,2,4 in listview lv2: 3,5
what I'm getting is 3,4,5 in both listviews
List<string> key = new List<string>();
List<long> val = new List<long>();
List<long> tempList = new List<long>();
Dictionary<string, List<long>> testList = new Dictionary<string, List<long>>();
key.Add("a");
key.Add("a");
key.Add("b");
key.Add("a");
key.Add("b");
val.Add(1);
val.Add(2);
val.Add(3);
val.Add(4);
val.Add(5);
for (int index = 0; index < 5; index++)
{
if (testList.ContainsKey(key[index]))
{
testList[key[index]].Add(val[index]);
}
else
{
tempList.Clear();
tempList.Add(val[index]);
testList.Add(key[index], tempList);
}
}
lv1.ItemsSource = testList["a"];
lv2.ItemsSource = testList["b"];
Solution:
replace the else code section with :
testList.Add(key[index], new List { val[index] });
thx everybody for your help =)

You are using the same list for both keys in the Dictionary
for (int index = 0; index < 5; index++)
{
if (testList.ContainsKey(key[index]))
{
testList[k].Add(val[index]);
}
else
{
testList.Add(key[index], new List<long>{val[index]});
}
}
Just create one new List(Of Long) when the key doesn't exists then add the long value to it

Get rid of the tempList and replace your else clause with:
testList.Add(key[index], new List<long> { val[index] });
And don't use Contains. TryGetValue is much better:
for (int index = 0; index < 5; index++)
{
int k = key[index];
int v = val[index];
List<long> items;
if (testList.TryGetValue(k, out items))
{
items.Add(v);
}
else
{
testList.Add(k, new List<long> { v });
}
}

Replace else with:
else
{
tempList.Clear();
tempList.Add(val[index]);
testList.Add(key[index], new List<long>(tempList));
}
The problem is, you are adding a reference to TempList to both keys, it is the same reference so it gets replaced in the first one.
I am creating a new list so it doesn't get replaced: new List<long>(tempList)

Sounds like a homework problem, but
for (int index = 0; index < 5; index++)
{
if (!testList.ContainsKey(key[index]))
testList.Add(key[index], new List<string> {value[index]});
else
testList[key[index]].Add(value[index]);
}
Read this (and the other relevant tutorials)

I'm not completely sure what you are trying to do here, but I guarantee you didn't want the same list in every dictionary entry.
templist is your problem swap templist.Clear() for templist = new List<Long>()
Or go for
for (int index = 0; index < 5; index++)
{
if (!testList.ContainsKey(key[Index]))
{
testList.Add(key[Index], new List<Long>());
}
testList[key[index]].Add(val[index]);
}

Related

Generate combinations of elements held in multiple list of strings in C#

I'm trying to automate the nested foreach provided that there is a Master List holding List of strings as items for the following scenario.
Here for example I have 5 list of strings held by a master list lstMaster
List<string> lst1 = new List<string> { "1", "2" };
List<string> lst2 = new List<string> { "-" };
List<string> lst3 = new List<string> { "Jan", "Feb" };
List<string> lst4 = new List<string> { "-" };
List<string> lst5 = new List<string> { "2014", "2015" };
List<List<string>> lstMaster = new List<List<string>> { lst1, lst2, lst3, lst4, lst5 };
List<string> lstRes = new List<string>();
foreach (var item1 in lst1)
{
foreach (var item2 in lst2)
{
foreach (var item3 in lst3)
{
foreach (var item4 in lst4)
{
foreach (var item5 in lst5)
{
lstRes.Add(item1 + item2 + item3 + item4 + item5);
}
}
}
}
}
I want to automate the below for loop regardless of the number of list items held by the master list lstMaster
Just do a cross-join with each successive list:
IEnumerable<string> lstRes = new List<string> {null};
foreach(var list in lstMaster)
{
// cross join the current result with each member of the next list
lstRes = lstRes.SelectMany(o => list.Select(s => o + s));
}
results:
List<String> (8 items)
------------------------
1-Jan-2014
1-Jan-2015
1-Feb-2014
1-Feb-2015
2-Jan-2014
2-Jan-2015
2-Feb-2014
2-Feb-2015
Notes:
Declaring lstRes as an IEnumerable<string> prevents the unnecessary creation of additional lists that will be thrown away
with each iteration
The instinctual null is used so that the first cross-join will have something to build on (with strings, null + s = s)
To make this truly dynamic you need two arrays of int loop variables (index and count):
int numLoops = lstMaster.Count;
int[] loopIndex = new int[numLoops];
int[] loopCnt = new int[numLoops];
Then you need the logic to iterate through all these loopIndexes.
Init to start value (optional)
for(int i = 0; i < numLoops; i++) loopIndex[i] = 0;
for(int i = 0; i < numLoops; i++) loopCnt[i] = lstMaster[i].Count;
Finally a big loop that works through all combinations.
bool finished = false;
while(!finished)
{
// access current element
string line = "";
for(int i = 0; i < numLoops; i++)
{
line += lstMaster[i][loopIndex[i]];
}
llstRes.Add(line);
int n = numLoops-1;
for(;;)
{
// increment innermost loop
loopIndex[n]++;
// if at Cnt: reset, increment outer loop
if(loopIndex[n] < loopCnt[n]) break;
loopIndex[n] = 0;
n--;
if(n < 0)
{
finished=true;
break;
}
}
}
public static IEnumerable<IEnumerable<T>> GetPermutations<T>(this IEnumerable<IEnumerable<T>> lists)
{
IEnumerable<IEnumerable<T>> result = new List<IEnumerable<T>> { new List<T>() };
return lists.Aggregate(result, (current, list) => current.SelectMany(o => list.Select(s => o.Union(new[] { s }))));
}
var totalCombinations = 1;
foreach (var l in lstMaster)
{
totalCombinations *= l.Count == 0 ? 1 : l.Count;
}
var res = new string[totalCombinations];
for (int i = 0; i < lstMaster.Count; ++i)
{
var numOfEntries = totalCombinations / lstMaster[i].Count;
for (int j = 0; j < lstMaster[i].Count; ++j)
{
for (int k = numOfEntries * j; k < numOfEntries * (j + 1); ++k)
{
if (res[k] == null)
{
res[k] = lstMaster[i][j];
}
else
{
res[k] += lstMaster[i][j];
}
}
}
}
The algorithm starts from calculating how many combinations we need for all the sub lists.
When we know that we create a result array with exactly this number of entries. Then the algorithm iterates through all the sub lists, extract item from a sub list and calculates how many times the item should occur in the result and adds the item the specified number of times to the results. Moves to next item in the same list and adds to remaining fields (or as many as required if there is more than two items in the list). And it continues through all the sub lists and all the items.
One area though that needs improvement is when the list is empty. There is a risk of DivideByZeroException. I didn't add that. I'd prefer to focus on conveying the idea behind the calculations and didn't want to obfuscate it with additional checks.

Handling multiple lists with if/else condition - recursion

i have many lists which contain 1 or more objects, and if there is more then 1 object in the list, it should do something. When there is only 1 object in the list, then take the second list and do the same. This should happen for 4 lists.
This is my Solution, but i think this is a bad solution. Is there a far better way on handling this code?
if (list1.Count > 1)
for (int i = 0; i < list1.Count; i++)
{
DoSomething(list1);
}
else
{
if (list2.Count > 1)
for (int i = 0; i < list2.Count; i++)
{
DoSomething(list2);
}
else
{
if (list3.Count > 1)
for (int i = 0; i < list3.Count; i++)
{
DoSomething(list3);
}
else
{
...
Many thanks and best regards,
Joerg
// using System.Collections.Generic;
// using System.Linq;
// create an enumerable "list" of your lists (however many there are):
var lists = new[] { list1, list2, list3, … };
// find the first list that has more than 1 element:
var list = lists.FirstOrDefault(_ => _.Count() > 1);
// if there is such a list…
if (list != null)
{
// … then `DoSomething` to each of its items:
foreach (var item in list)
{
DoSomething(item);
}
}
I tried to use same psuedo-code style as OP. The logic replicates the original, but in condensed form and with advantage of easily adding lists to the master list array (as suggested by #Benjamin).
It is assumed that DoSomething is a single function applied to the first list which has Count > 1. If you wanted to apply a custom function per list, you could create another array for holding the function to call for the corresponding list.
listArray = new[] {list1, list2, list3, list4}; // you can add more as needed to this master array
for (int i = 0; i < listArray.Count; i++)
{
if (listArray[i].Count > 1)
{
for (int i = 0; i < listArray.Count; i++)
{
DoSomething(listArray[i]);
}
break; // http://msdn.microsoft.com/en-us/library/adbctzc4.aspx
}
}
You can check first which list you want to use:
var lists = new[]{ list1, list2, list3, list4 };
var list = lists.FirstOrDefault(l => l.Count > 1);
if(list != null)
{
list.ForEach(l => DoSomething(list));
}
Seems like you need the first list for which Count > 1.
Also, inside the for-loop, you're saying DoSomething(list1);. I think it should be DoSomething(list1[i]);
var lists = new [] { list1, list2, list3, list4 };
var target = lists.FirstOrDefault(l => l.Count() > 1);
if (target != null) {
for (int i = 0; i < target.Count; i++)
{
DoSomething(target[i]);
}
} else {
//...
}

custom sorting in a bindinglist of keyvaluepairs

I have a bindinglist of keyvaluepair filled dynamicaly.
BindingList<KeyValuePair<int, string>> Homelist = new BindingList<KeyValuePair<int, string>>();
foreach (ListItem item in listBox2.Items)
{
Homelist.Add(new KeyValuePair<int, string>(item.Id, item.Name));
}
The list has key(id) and value(text) as shown
I want to sort the first 5 items asc and then the rest items also asc.the sorting must be by value and not by key.
example: if I have the values : 4,5,8,7,6,10,9,3,2,1,22 the sorting result must be 4,5,6,7,8 ,1,2,3,9,10,22.Any idea?
solved answer:
public int Compare(KeyValuePair<int,string> a, KeyValuePair<int,string> b)
{
return a.Value.CompareTo(b.Value);
}
List<keyvaluepair><int,>> Playinglist = new List<keyvaluepair><int,>>();
for (int i = 0; i < 5; i ++)
{
Playinglist.Add(Homelist[i]);
}
Playinglist.Sort(Compare);
List<keyvaluepair><int,>> Benchlist = new List<keyvaluepair><int,>>();
for (int i = 5; i < Homelist.Count(); i++)
{
Benchlist.Add(Homelist[i]);
}
Benchlist.Sort(Compare);
//union 2 lists
var unionedList = new List<keyvaluepair><int,>>();
unionedList.AddRange(Playinglist.Union(Benchlist));
Homelist.Clear();
for (int i = 0; i < unionedList.Count(); i++)
{
Homelist.Insert(i, unionedList[i]);
}
game.GetHomelist = Homelist;
The idea that Tony Hopkinson said is to chop the list into two. Sort them separately and then join them back togther.After that clear the bindlist and filled from the join list. Sorting can be applied only in List<> and not to the BindLists<>.The answere is in edited question

Change Key for a SortedList

I need a Sorted list, but after I remove an item from the list I then need to adjust the keys of the other items before adding new items to the list.
You are not allowed to change the key for the items in a "SortedList".
What tool would be best for doing this.
Example code
timedEvQue.Add(3, "First");
timedEvQue.Add(7, "Second");
timedEvQue.Add(9, "Third");
int decAmnt = (int)timedEvQue.Keys[0];
timedEvQue.RemoveAt(0);
for (int i = 0; i < timedEvQue.Count; ++i)
{
timedEvQue.Keys[i] = timedEvQue.Keys[i] - decAmnt; //runtime error here
}
timedEvQue.Add(5, "Forth");
There isn't typically a change key operation for dictionary/hash map type data structures as they would essentially just remove and add the item again. So just remove and add the item back.
timedEvQue.Add(3, "First");
timedEvQue.Add(7, "Second");
timedEvQue.Add(9, "Third");
int decAmnt = (int)timedEvQue.Keys[0];
timedEvQue.RemoveAt(0);
for (int i = 0; i < timedEvQue.Count; ++i)
{
int oldKey = timedEvQue.Keys[i];
string val = timedEvQue[oldKey];
int newKey = oldKey - decAmnt;
timedEvQue.Remove(oldKey);
timedEvQue.Add(newKey, val);
}
timedEvQue.Add(5, "Forth");

Using sortedList to count words in a List

For my homework, I have to use a SortedList to count words in a List with SortedList taking each entry and sorting it in alphabetical order before inserting. When it comes to display the data to the user, the data displayed should be displayed with sorting according to value instead of key.
Below is my attempt at this but I am getting 3 errors and I don't know how to resolve it. I am not allowed to use LINQ for this.
List<string> words = new List<string>(); <--- Already populated
This is my code of this implementation and I get 3 errors:
SortedList<string, int> d = new SortedList<string, int>();
bool InsideOfList = false;
foreach (string word in words)
{
InsideOfList = false;
foreach (KeyValuePair<string, int> keyvalPair in d)
{
if (keyvalPair.Key == word)
{
keyvalPair.Value += 1;
InsideOfList = true;
}
}
if (InsideOfList == false)
{
d.Add(word,1);
}
}
//Now instead of sorting by key I want to sort by value instead
SortedList<int, string> tempSortList = new SortedList<int, string>();
foreach (KeyValuePair<string, int> keyvalPair in d)
{
//trying to swap the value of previous SortedList with the Key of the new SortedList
tempSortList.Add(keyvalPair.Value, keyvalPair.Key);
}
for (int i = 0; i < 20; i++)
{
Console.WriteLine("\t{0}:\t{1}", tempSortList.GetKey(i), tempSortList.GetByIndex(i));
}
Here are my errors:
Property or indexer 'System.Collections.Generic.KeyValuePair<string,int>.Value' cannot be assigned to -- it is read only
'System.Collections.Generic.SortedList<int,string>' does not contain a definition for 'GetKey'
'System.Collections.Generic.SortedList<int,string>' does not contain a definition for 'GetByIndex'
You are confusing two things here. One is SortedList() and other is SortedList().
GetKey and GetKeyList are not present in SortedList(). You can use this instead of GetKey
tempSortList.ElementAt(index); // This will return you a KeyValuePair.
And for the first error you cannot assign value keyvalPair.Value has only getter. So you cannot set its value by doing += 1.
This is not quite good. Needs some improvement but it will work.
for (int i = 0; i < d.Count; i++)
{
if (d.ElementAt(i).Key == word)
{
d.Values[i] += 1;
}
}
or
for (int i = 0; i < d.Count; i++)
{
if (d.ElementAt(i).Key == word)
{
var val = d.ElementAt(i).Value + 1;
d.RemoveAt(i);
d.Add(word, val);
}
}
Please modify this line and check if it works. it should.
Console.WriteLine("\t{0}:\t{1}", tempSortList.GetKey(i), tempSortList.GetByIndex(i));
to
var key = tempSortedList.Keys[i];
var value = tempSortedList.Values[i];
Console.WriteLine("\t{0}:\t{1}", key, value);

Categories