C# Merging dictionaries inside of an object - c#

I realize there are tons of posts on this subject but I still haven't found what I am looking for reading the answers.
I get two objects A and B, that both have a dictionary and a set of booleans. Dictionaries are shaped the same, just the data differs. My end goal here is to create a 3rd object C, copy of A with its dictionary updated to have values from A and B according to a set of rules (for instance C.dictionary would have all A.dictionary.[x] if A.Dictionary.[x].Value.days < 5 and and all B.dictionary.[x] if days > 5).
If you have a solution for this that would be awesome, otherwise, here is where I am at and where I fail:
I am trying to create a new dictionary and and loop through A and B to add the values... I'll add the rules after. Once I will have it I'll find a way to place this dictionary into object C. (tell me if over engineered, I am very new to C#).
var dict = new Dictionary<DateTime, TypeData>();
foreach (var item in A.dictionary.keys)
{
dict.Add(A.Dictionary[item]);
}
This does not work for 2 reasons:
item does represents A.dictionary[x].key not A.dictionary[x] (also contains value and non public members)
"Add" gets underlines and does not show more info for the error
Thanks a lot for checking my post !

try this
var dictionariesToCombine = new Dictionary<DateTime, TypeData>[] {dictA,dictB};
Dictionary<int, int> dictC = new Dictionary<DateTime, TypeData>();
for (var i=0; i< dictionariesToCombine.Length; i++)
{
foreach (var item in dictionariesToCombine[i])
{
if(
(i==0 and your conditions)
|| (i==1 and your conditions)
)
resultDict.Add(item.Key, item.Value);
}
}

Related

C# dictionary value is updating automatically

In my recent project im trying to make a dictionary with key as a string and value as List of string(List) and adding value in dictionary using for loop ,
but the problem is that after first iteration when I Update the List for second iteration it is automatically changing in the first key value pair.
for example in first iteration it is saving key as apple and value as list {cucumber,chilli,tomato,apple} its fine but after first iteration when i update list to {cucumber,chilli,tomato,apple,mango} and saving it to second key mango it is also updating the first value to {cucumber,chilli,tomato,apple,mango}.
var mylist = new List<string>()
{
"cucumber",
"chilli",
"tomato"
};
var yourlist = new List<string>()
{
"apple",
"mango",
"banana"
};
var dict = new Dictionary<string, List<string>>();
foreach (var i in yourlist)
{
mylist.Add(i);
dict.Add(i,mylist);
}
foreach(var d in dict.Keys)
{
foreach(var l in dict[d])
{
Console.WriteLine(l);
}
}
The dictionary entries' Value properties are always the same list, so anything you do to one, ends up showing in all of them (because there is only one)
Take a look at the code below; if you understand why a and b here both show the same change, then you should understand that your dictionary scenario is essentially the same
var list = new List<string>(){ "hello", "world" };
var a = list;
var b = list;
a.Add("there");
Console.Write(b.Count); //shows 3
If you don't understand why a, b and list above all refer to the same list, then drop a comment and I'll add some more explanation
As to what you should do about your "issue", it's not entirely clear to me what you're hoping to do but if you made sure that each key in the dictionary associated with a new list rather than the same one, then changes to one key's list would not show in other keys' lists:
dict.Add(i, new List<string>(mylist));
This makes a new list per key, and initializes the new list with the items present in mylist at the time (my list grows each pass of the loop)

How to... 2 dimensional matrix using object as index?

If have 2 classes, Teams and Games.
Something like this:
class Team {...}
class Games
{
Team team1;
Team team2;
...
}
And I have a List of all games played...
List<Games> allGames ...
What I now want to do is: for further statistics I need a matrix that counts how often each team played against every other team.
Earlier I would have solved this as follows:
int[,] countTeamVsTeam = new int[allTeams.Count, allTeams.Count];
foreach (Game game in allGames)
{
countTeamVsTeam[game.team1.SOMENUMBER,game.team2.SOMENUMBER]++;
}
Now I wonder if it is a good idea to skip that artificial SOMENUMBER attribute and use the objects by themselves as an index of my data structure:
Dictionary<Team, Dictionary<Team, int>> countTeamVsTeam = new Dictionary<Team, Dictionary<Team, int>>();
// initialize
foreach (Team team1 in allTeams)
{
countTeamVsTeam[team1] = new Dictionary<Team, int>();
foreach (string team2 in allTeams)
{
countTeamVsTeam[team1][team2] = 0;
}
}
foreach (Game game in allGames)
{
countTeamVsTeam[game.team1,game.team2]++;
}
Any thoughts on this?
Is this a good way of doing it?
Is that Dictionary<Team, Dictionary<Team, int>> a good data structure for representing the 2 dimensional matrix? (yes I know it's not an array but a dictionary of dictionaries...)
I see a couple of options.
A Dictionary can actually have a tuple/composite key so you can define it as follows
Dictionary<(Team, Team), int> countTeamVsTeam = new Dictionary<(Team, Team), int>();
But as pointed out in the comments above, you need to strictly control the order of each team (home vs away, alphabetical, ordered by id etc.) as
countTeamVsTeam[(team1, team2)] will not have the same value as countTeamVsTeam[(team2, team1)]
Another option is to create a custom collection. Within which you internally control the teams in a manner that is not visible externally so that you can abstract this detail and control the order of the teams so that you only store a single value no matter which order the teams are passed into the collection.

Odd behavior with the List/Dictionary .Clear() method [duplicate]

This question already has answers here:
Why does adding a new value to list<> overwrite previous values in the list<>
(2 answers)
Closed 4 years ago.
I have a code block similar to this:
List<Object> returnObjDataLine = new List<object>();
foreach (var tuple in dataPerTime)
{
returnObjDataLine.Clear();
returnObjDataLine.Add(tuple.Item1);
foreach (var line in PlotLines)
{
if (tuple.Item2.Equals(line.Key))
{
returnObjDataLine.Add(tuple.Item3);
}
else
{
returnObjDataLine.Add(null);
}
}
returnObjData.Add(returnObjDataLine);
}
However the Clear() method clears out the data already added to the returnObjData Dictionary, sort of. If there are 10,000 tuples, then after the loop runs the returnObjData will contain 10,000 instances of the very last data piece added (Clear() is not called after the last iteration).
If I modify the code to create a new List each iteration:
foreach (var tuple in dataPerTime)
{
List<Object> returnObjDataLine = new List<object>();
returnObjDataLine.Add(tuple.Item1);
foreach (var line in PlotLines)
{
if (tuple.Item2.Equals(line.Key))
{
returnObjDataLine.Add(tuple.Item3);
}
else
{
returnObjDataLine.Add(null);
}
}
returnObjData.Add(returnObjDataLine);
}
the loading loop works correctly but this seems very expensive as there can be 10s if not 100s of thousands of iterations required. Creating a new object every time seems to be inefficient.
What am I missing with Clear()? Is there some sort of "commit" that needs to be called first?
Looks like what you need to do is have a temporary list and a long term list... Something like this:
List<Object> longTermObjects = new List<object>();
foreach (var tuple in dataPerTime)
{
List<Object> returnObjDataLine = new List<Object>();
returnObjDataLine.Add(tuple.Item1);
foreach (var line in PlotLines)
{
if (tuple.Item2.Equals(line.Key))
{
returnObjDataLine.Add(tuple.Item3);
}
else
{
returnObjDataLine.Add(null);
}
}
longTermObjects.Add(returnObjDataLine);
}
This will give you a clean returnObjDataLine each iteration without removing the referenced items in longTermObjects.
Edit To Add Reference Type Information:
By default .NET will store 1 copy of an object into memory, and then "reference" that object anywhere you use it. Take the following example:
int A = 1;
int B = A;
Console.WriteLine($"A = {A}");
Console.WriteLine($"B = {B}");
A = 0;
Console.WriteLine($"A = {A}");
Console.WriteLine($"B = {B}");
Result:
A = 1
B = 1
A = 0
B = 0
Why you ask does B = 0 on the 4th line? Because B had a REFERENCE to A, it didn't contain the actual VALUE of A, so when A changed, B changed as well.
If I wanted B to contain only the value of A then I would need a way to create a new "value" instead of a reference. The way you do this varies for each type of object. One way and probably not the best would be something like:
int B = int.Parse(A.ToString());
Which would convert A to a string representing the value of A and then into a new int with the Parse. Now I have the value stored in B instead of just a reference.
If I wanted to do the same thing with a table of objects then I would have to do something like this:
List<MyObject> oldList = new List<MyObject>();
//Put some objects into oldList
List<MyObject> newList = oldList.Select(x => new MyObject(x.Param1, x.Param2)).ToList();
In this example I am basically taking each object in oldList and creating a new MyObject which is then put into newList.

Arrays/Array Lists

I am fairly new to C#
I am trying to retrieve some information from an external data source and store it in array, once it is in an array I wish to sort it by time.
I know how to do this for just one column in a row, however the information I require has multiple columns.
For example:
foreach (Appointment Appoint in fapts)
{
// Store Appoint.Subject, Appoint.Start, Appoint.Organiser.Name.ToString(), Appoint.Location in an array
}
// Sort my array by Appoint.Start
foreach ( item in myNewArray )
{
//print out Appoint.Subject - Appoint.Start, Appoint.Organiser.Name.ToString() and Appoint.location
}
Many thanks for your help.
EDIT:
I have multiple data sources which pull in this:
foreach (Appointment Appoint in fapts)
{
// Store Appoint.Subject, Appoint.Start, Appoint.Organiser.Name.ToString(), Appoint.Location in an array
}
Hence the need to sort the items in a new array, I know this isn't very efficent but there is no way of getting the information I need in any other way.
You can sort a list using the LINQ sorting operators OrderBy and ThenBy, as shown below.
using System.Linq;
and then...
var appointments = new List<Appointment>();
var sortedAppointments = list.OrderBy(l => l.Subject).ThenBy(l => l.Name).ToList();
This will create a new list of appointments, sorted by subject and then by name.
It's unclear what your final aim is but:
Use a generic List instead of an array:
See this SO question for more information as to why using a List is prefered.
List<Appointment> appointments = new List<Appointment>();
foreach (Appointment Appoint in fapts)
{
appointments.Add(Appoint);
}
foreach (var item in appointments)
{
Console.WriteLine(item.Subject);
Console.WriteLine(item.Foo);
// Here you could override ToString() on Appointment to print eveything in one Console.WriteLine
}
If the aim of your code is to order by time, try the following:
var sortedAppointments = fapts.OrderBy(a => a.Start); // assuming Start is a DateTime property of `Appointment`.
Consider a Dictionary Object instead of an array if the data is conceptually one row multiple columns.
foreach(KeyValuePair<string, string> entry in MyDic)
{
// do something with entry.Value or entry.Key
}
You already have a list of objects in fpts, sort that list itself:
fpts.OrderBy(x => x.Subject).ThenBy(x => x.Location).ToList();
LINQ is your friend here.
fapts appears to already be a collection so you could just operate on it.
var myNewArray = fapts.OrderBy(Appoint => Appoint.Start).ToArray()
I've used the ToArray() call to force immediate evaluation and means that myNewArray is already sorted so that if you use it more than once you don't have to re-evaluate the sort.
Alternatively if you are only using this once you can just as easily miss the ToArray() portion out and then execution of the sort will be deferred until you try and enumerate through myNewArray.
This solution puts the source objects into the array, but if you are just wanting to store the specific fields you mention then you will need to use a select. You have two choices for the array item type, you can either use an anonymous class which provides difficulties if you are returning this array from a function or define a class.
For anonymous:
var myNewArray = fapts.OrderBy(Appoint => Appoint.Start)
.Select(Appoint => new {
Start = Appoint.Start,
Organiser = Appoint.Organiser.Name.ToString(),
Location = Appoint.Location
}).ToArray();
For named class assuming class is MyClass:
var myNewArray = fapts.OrderBy(Appoint => Appoint.Start)
.Select(Appoint => new MyClass {
Start = Appoint.Start,
Organiser = Appoint.Organiser.Name.ToString(),
Location = Appoint.Location
}).ToArray();
You have a wide range of options. The 2 most common are:
1) Create a class, then define an array or list of that class, and populate that
2) Create a structure that matches the data format and create an array or list of that
Of course, you could put the data into an XML format or dataset, but that's probably more work than you need.
public List<foo> appointments = new List<foo>();
public struct foo
{
public string subject ;
public DateTime start ;
public string name ;
public string location ;
}
public void foo1()
{
// parse the file
while (!File.eof())
{
// Read the next line...
var myRecord = new foo() ;
myRecord.subject = data.subject ;
myRecord.start = data.Start ;
myRecord.name = data.Name ;
//...
appointments.Add(myRecord);
}
}
Enjoy
(Since I can't comment and reply to the comment - it wasn't clear if he had a class, etc. or was just showing us what he wanted to do. I assumed it was just for demonstration purposes since there wasn't any info as to how the data was being read. If he could already put it into a class, than the first answer applied anyway. I just tossed the last 2 in there because they were options for getting the data first.)

Iterating over a growing dictionary

I am working with C# and I have a dictionary called intervalRecordsPerObject of type Dictionary<string, List<TimeInterval>>. I need to iterate through the dictionary. The problem is: everytime I iterate through the dictionary, more KeyValuePairs may get added to it. As the dictionary grows, I need to keep iterating over the new entries too.
Firstly, I did this: A simple foreach loop that gave me an InvalidOperationException saying
Collection was modified; enumeration operation may not execute.
I know I cannot iterate over the Dictionary this way if it keeps changing as C# converts it with ToList() before foreach loop.
I know I can copy the keys to a temporary array, iterate over the dictionary using simple for loop and Count and whenever a new entry is added to the dictionary, add the corresponding key to the array too. Now, the problem is a simple array cannot grow dynamically and I don't know beforehand what the required size could be.
To move ahead, I thought I'd do this:
List<string> keyList = new List<string>(intervalRecordsPerObject.Count);
intervalRecordsPerObject.Keys.CopyTo(keyList.ToArray(), 0);
I cannot do this either. keyList is currently empty and therefore keyList.toArray() returns an array of length 0 which gives me an ArgumentException saying
Destination array is not long enough to copy all the items in the
collection. Check array index and length.
I am stuck! Any idea what more can I try? Thanks for any help.
Addition 1:
The dictionary stores the time intervals for which a particular object is present. Key is the ID of the object. New entries may get added in every iteration (worst case) or may not get added even once. Whether or not entries are added is decided by a few conditions (whether the object overlaps with some other intervals, etc.). This triggers a change in the ID and the corresponding interval list which is then added as a new entry to the dictionary.
Something like this:
List<string> keys = dict.Keys.ToList();
for (int i = 0; i < keys.Count; i++)
{
var key = keys[i];
List<TimeInterval> value;
if (!dict.TryGetValue(key, out value))
{
continue;
}
dict.Add("NewKey", yourValue);
keys.Add("NewKey");
}
The trick here is that you enumerate the List<T> by index! In this way, even if you add new elements, the for (...) will "catch" them.
Other possible solution, by using a temporary Dictionary<,>:
// The main dictionary
var dict = new Dictionary<string, List<TimeInterval>>();
// The temporary dictionary where new keys are added
var next = new Dictionary<string, List<TimeInterval>>();
// current will contain dict or the various instances of next
// (multiple new Dictionary<string, List<TimeInterval>>(); can
// be created)
var current = dict;
while (true)
{
foreach (var kv in current)
{
// if necessary
List<TimeInterval> value = null;
// We add items only to next, that will be processed
// in the next while (true) cycle
next.Add("NewKey", value);
}
if (next.Count == 0)
{
// Nothing was added in this cycle, we have finished
break;
}
foreach (var kv in next)
{
dict.Add(kv.Key, kv.Value);
}
current = next;
next = new Dictionary<string, List<TimeInterval>>();
}
You can access the Keys by positions rather than by content and use a normal For loop (allowing additions/removals without any restriction).
for (int i = 0; i < dict.Keys.Count; i++)
{
string curKey = dict.Keys.ElementAt(i);
TimeInterval curVal = dict.Values.ElementAt(i);
//TimeInterval curVal = dict[curKey];
//Can add or remove entries
}

Categories