Pass by reference issue using a delegate inside a loop - c#

I have the following code which creates and returns a Dictionary<int, List<string>>
private static readonly Random rnd = new Random();
private static Dictionary<int, List<string>> GenerateValues(string entityType, int rows)
{
var values = new Dictionary<int, List<string>>();
var baseValues = new List<string> { "99 Hellesdon Road","Home","Norfolk","NR6 5EG","Norwich" };
Action<int> rowLoop = null;
switch (entityType)
{
case "Employer":
rowLoop = (row) =>
{
var employer = new List<string>
{
$"Employer {rnd.Next(10000, 99999)}",
$"{rnd.Next(100000000, 999999999)}",
"TRUE"
};
var rowValue = baseValues;
rowValue.AddRange(employer);
values.Add(row, rowValue);
};
break;
case "AssessmentCentre":
rowLoop = (row) =>
{
var rowValue = baseValues;
rowValue.Add($"Assessment Centre {rnd.Next(10000, 99999)}");
values.Add(row, rowValue);
};
break;
}
for (int i = 1; i <= rows; i++)
{
rowLoop(i);
}
return values;
}
And then to call it with...
var spreadsheetValues = GenerateValues("Employer", 5);
Then intention for the code is to have some base values stored in a List<string>, then depending on what entityType is passed into the method, add some additional values to those base values. Then loop round a certain number of rows to create the Dictionary<int, List<string>>, where int is the row number.
The issue I'm having is that baseValues is being updated during each iteration of my for loop. I didn't expect this when using var rowValue = baseValues;
This is a debug screenshot of the last item in the collection....
I am expecting each List<string> in Dictionary<int, List<string>> to contain 8 items, but instead it is growing with each iteration.
Why is this occurring and how might I correct it?

It seems like you are already on track with the solution to your problem but here is a way to solve it.
Where you write
var rowValue = baseValues;
you are really just making "rowValue" a pointer to "baseValues". To make a copy, you could do something like this:
var rowValue = baseValues.ToList();

Related

Merge List of columns and List of Data into List C#

I am facing some problem to merge two lists into a single list by using LINQ and C#.
My scenario is that in List one I got the number of columns and in second list I am getting data correspondent column list.
The similarity between the two lists is their indexes.
Currently, I am using List of the dictionary to do this job but I need data as a model list.
Here is my code
/* Loop over the result set and create a dictionary with column name for key and data for value */
List<Dictionary<String, String>> scanLists = new List<Dictionary<String, String>>();
if (resResp.ResultSet.Rows.Count > 1)
{
/*First cloumn always contains column names so we have to remove those*/
//resResp.ResultSet.Rows.Remove(resResp.ResultSet.Rows[0]);
foreach (Row row in resResp.ResultSet.Rows)
{
Dictionary<String, String> scanData = new Dictionary<String, String>();
for (var i = 0; i < resResp.ResultSet.ResultSetMetadata.ColumnInfo.Count; i++)
{
scanData.Add(resResp.ResultSet.ResultSetMetadata.ColumnInfo[i].Name, row.Data[i].VarCharValue);
}
scanLists.Add(scanData);
}
}
But I want result in in
List<ScanData> scanList = new List<ScanData>();
Thank you ALL
Try a homegrown Object-Relational Mapping:
var scanObjects = new List<MyCustomObject>();
foreach (Row row in resResp.ResultSet.Rows)
{
var myObject = new MyCustomObject();
//Dictionary<String, String> scanData = new Dictionary<String, String>();
for (var i = 0; i < resResp.ResultSet.ResultSetMetadata.ColumnInfo.Count; i++)
{
//scanData.Add(resResp.ResultSet.ResultSetMetadata.ColumnInfo[i].Name, row.Data[i].VarCharValue);
switch( resResp.ResultSet.ResultSetMetadata.ColumnInfo[i].Name )
{
case "ExampleId":
myObject.ExampleId = row.Data[i].VarCharValue;
break;
case "ExampleValue":
myObject.ExampleValue = row.Data[i].VarCharValue;
break;
default:
// Unrecognised/unused column
break;
}
}
//scanLists.Add(scanData);
scanObjects.Add(myObject);
}

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);

Convert array of strings to Dictionary<string, int> c# then output to Visual Studio

I have an array of strings like so:
[0]Board1
[1]Messages Transmitted75877814
[2]ISR Count682900312
[3]Bus Errors0
[4]Data Errors0
[5]Receive Timeouts0
[6]TX Q Overflows0
[7]No Handler Failures0
[8]Driver Failures0
[9]Spurious ISRs0
just to clarify the numbers in the square brackets indicate the strings position in the array
I want to convert the array of strings to a dictionary with the string to the left of each number acting as the key, for example (ISR Count, 682900312)
I then want to output specific entries in the dictionary to a text box/table in visual studio (which ever is better) it would be preferable for the numbers to be left aligned.
excuse my naivety, I'm a newbie!
Pretty Simple. Tried and Tested
string[] arr = new string[] { "Board1", "ISR Count682900312", ... };
var numAlpha = new Regex("(?<Alpha>[a-zA-Z ]*)(?<Numeric>[0-9]*)");
var res = arr.ToDictionary(x => numAlpha.Match(x).Groups["Alpha"],
x => numAlpha.Match(x).Groups["Numeric"]);
string[] strings =
{
"Board1", "Messages232"
};
Dictionary<string, int> dictionary = new Dictionary<string, int>();
foreach (var s in strings)
{
int index = 0;
for (int i = 0; i < s.Length; i++)
{
if (Char.IsDigit(s[i]))
{
index = i;
break;
}
}
dictionary.Add(s.Substring(0, index), int.Parse(s.Substring(index)));
}
var stringArray = new[]
{
"[0]Board1",
"[1]Messages Transmitted75877814",
"[2]ISR Count682900312",
"[3]Bus Errors0",
"[4]Data Errors0",
"[5]Receive Timeouts0",
"[6]TX Q Overflows0",
"[7]No Handler Failures0",
"[8]Driver Failures0",
"[9]Spurious ISRs0"
};
var resultDict = stringArray.Select(s => s.Substring(3))
.ToDictionary(s =>
{
int i = s.IndexOfAny("0123456789".ToCharArray());
return s.Substring(0, i);
},
s =>
{
int i = s.IndexOfAny("0123456789".ToCharArray());
return int.Parse(s.Substring(i));
});
EDIT: If the numbers in brackets are not included in the strings, remove .Select(s => s.Substring(3)).
Here you go:
string[] strA = new string[10]
{
"Board1",
"Messages Transmitted75877814",
"ISR Count682900312",
"Bus Errors0",
"Data Errors0",
"Receive Timeouts0",
"TX Q Overflows0",
"No Handler Failures0",
"Driver Failures0",
"Spurious ISRs0"
};
Dictionary<string, int> list = new Dictionary<string, int>();
foreach (var item in strA)
{
// this Regex matches any digit one or more times so it picks
// up all of the digits on the end of the string
var match = Regex.Match(item, #"\d+");
// this code will substring out the first part and parse the second as an int
list.Add(item.Substring(0, match.Index), int.Parse(match.Value));
}

Mapping from 2D array in C#

I want to use a 2-D array in C#, e.g:
string[,] a = new string[,]
{
{"aunt", "AUNT_ID"},
{"Sam", "AUNT_NAME"},
{"clozapine", "OPTION"},
};
My requirement is that when I pass "aunt" to this array I want to get corresponding AUNT_ID from the 2-D array.
As others have said, a Dictionary<string, string> would be better - and you can use a collection initializer to create it simply:
Dictionary<string, string> dictionary = new Dictionary<string, string>
{
{"ant", "AUNT_ID"},
{"Sam", "AUNT_NAME"},
{"clozapine", "OPTION"},
};
If you're confident that your key is in the dictionary, and you're happy for an exception to be thrown otherwise:
string value = dictionary[key];
or if it might not be:
string value;
if (dictionary.TryGetValue(key, out value))
{
// Use value here
}
else
{
// Key wasn't in dictionary
}
If you really need to use an array, if you can change it to a multidimensional array (string[][]), you can use:
// Will throw if there are no matches
var value = array.First(x => x[0] == key)[1];
Or again to be more circumspect:
var pair = array.FirstOrDefault(x => x[0] == key);
if (pair != null)
{
string value = pair[1];
// Use value here
}
else
{
// Key wasn't in dictionary
}
LINQ unfortunately doesn't work quite as well on rectangular arrays. It probably wouldn't be too hard to write a method to allow it to be treated "somewhat" like an array of arrays, admittedly...
Use Dictionary<string, string> for that:
Dictionary<string, string> arr = new Dictionary<string, string>();
arr.Add("ant", "AUNT_ID");
arr.Add("Sam", "AUNT_NAME");
arr.Add("clozapine", "OPTION");
string k = arr["ant"]; // "AUNT_ID"
The best option for you is to use Dictionary, but if you still wants to use 2D array, you may try the following
string[,] a = new string[,]
{
{"ant", "AUNT_ID"},
{"Sam", "AUNT_NAME"},
{"clozapine", "OPTION"},
};
string search = "ant";
string result = String.Empty;
for (int i = 0; i < a.GetLength(0); i++) //loop until the row limit
{
if (a[i, 0] == search)
{
result = a[i, 1];
break; //break the loop on find
}
}
Console.WriteLine(result); // this will display AUNT_ID
It looks rather like you want a dictionary:
Dictionary<string, string> a = new Dictionary<string, string>();
a.Add("ant", "AUNT_ID");
a.Add("Sam", "AUNT_NAME");
a.Add("clozapine", "OPTION");
string s = a["ant"]; // gets "AUNT_ID"
To check if a key exists in the dictionary:
if (a.ContainsKey("ant")) {
...
}
Or:
string s;
if (a.TryGetValue("ant", out s)) {
...
}
for (i=0; i<3; i++){
if (!String.Compare(a[i][0], string)){
stored_string= a[i][1];
}
}

Convert Dictionary<string, string> to CSV File. Keys as Row 1 and Values as row value for the columns

I have a C# Dictionary which I create by reading multiple data sources. The Dictionary contains key value pairs where the value collection of a key is a comma seperated string value.
for example:
Dictionary<string, string> d = new Dictionary<string, string>();
d.Add("cat", "2,2");
d.Add("dog", "10, A");
d.Add("llama", "A,B");
d.Add("iguana", "-2,-3");
I want the final csv file to look like this:
cat, dog, llama, iguana
2,10,A,-2
2,A,B,-3
How do I achieve this?
It would be easier if your data structure was Dictionary, otherwise you'll need to split out the items in advance or do it multiple times in a loop. A List would work also. Depending on how you're getting the data in from your data sources should determine whether it is easier to do a String.Split() on the data coming in (e.g. it's already a delimited string), or whether each item is being added individually.
This code could be optimized (e.g. get rid of the dictionary lookups each time through the loops) and cleaned up, but should get you started, and should be fine if your data set is not too large:
static void Main(string[] args)
{
Dictionary<string, string[]> d = new Dictionary<string, string[]>();
d.Add("cat", new string[] { "2", "2" });
d.Add("dog", new string[] { "10", "A" });
d.Add("llama", new string[] { "A", "B" });
d.Add("iguana", new string[] { "-2", "-3" });
// Not clear if you care about the order - this will insure that the names are in alphabetical order.
// The order of items in a dictionary are not guarenteed to be the same as the order they were added.
var names = d.Keys.OrderBy(l => l).ToList();
// Not clear if you know the number of items that will be in the list in advance - if not, find the max size
int maxSize = d.Values.Max(a => a != null ? a.Length : 0);
Console.WriteLine(String.Join(", ", names));
for (int i = 0; i < maxSize; i++)
{
foreach (string name in names)
{
string[] value = d[name];
if ((value != null) && (i < value.Length))
{
Console.Write(value[i]);
}
if (name != names.Last())
{
Console.Write(",");
}
}
Console.WriteLine();
}
}
Will generate this output:
cat, dog, iguana, llama
2,10,-2,A
2,A,-3,B
A Dictionary used in a foreach will return a KeyValuePair ... where you can access the "Key" and "Value". For the extracting of the "value" you can use string.Split(). The rest should be relativly easy depending on what you exactly need.
[Edit]
And finally you just open a text file for write, and dump the data out the way you want.
Dictionary<string, List<string>> d = new Dictionary<string, List<string>>();
d.Add("cat", new List<string> {"2", "2"});
d.Add("dog", new List<string> {"10", "A"});
d.Add("llama", new List<string>{"A","B"});
d.Add("iguana", new List<string>{"-2","-3"});
List<List<string>> values = d.Values.AsQueryable().ToList();
int count = values[0].Count;
for (int i = 0; i < count; i++)
{
for (int j = 0; j < values.Count; j++)
{
Console.Write(values[j].ElementAt(i));
}
}
Ommited checks and formatting but this does what you want.

Categories