So I wrote a test code (trying to teach myself how to make sorting algorithms), which looks like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp2
{
class Program
{
static string Compile (List<int> array)
{
string output = "";
foreach (var item in array)
{
output += item.ToString() + " ";
}
return output;
}
static List<int> InsertSort(List<int> listToSort)
{
List<int> deliverList = new List<int>();
deliverList = listToSort;
int j = 0;
int iterator = 0;
for (int i = 1; i < deliverList.Count; i++)
{
j = i;
while(j>0)
{
if(deliverList[j] < deliverList[j-1])
{
int temp = deliverList[j - 1];
deliverList[j - 1] = deliverList[j];
deliverList[j] = temp;
}
Console.WriteLine("Iteration #[" + iterator.ToString() + "]: " + Compile(deliverList));
iterator++;
j--;
}
}
return deliverList;
}
static void Main(string[] args)
{
List<int> unsorted = new List<int>();
List<int> sorted = new List<int>();
Random random = new Random();
for (int i = 0; i < 10; i++)
{
unsorted.Add(random.Next(0, 100));
}
sorted = InsertSort(unsorted);
Console.WriteLine("Unsorted Array: " + Compile(unsorted));
Console.WriteLine("Sorted Array: " + Compile(sorted));
Console.ReadKey();
}
}
}
For some reason, when I use the InsertSort method on the "sorted" array, the "unsorted" array is also changed, outputting the sorted array two times and not letting me see the unsorted one. What exactly is happening here?
PS: Compile is just a simple method that compiles a list into a string with the elements separated by spaces.
You have the code deliverList = listToSort; which makes deliverList reference the same list as listToSort. They become synonyms.
Instead you should write:
List<int> deliverList = listToSort.ToList();
That will make a copy of the list - and now they will both be different.
Your code now would output:
Iteration #[0]: 52 88 93 69 35 21 63 47 2 17
Iteration #[1]: 52 88 93 69 35 21 63 47 2 17
...
Iteration #[43]: 2 17 21 35 47 52 63 69 88 93
Iteration #[44]: 2 17 21 35 47 52 63 69 88 93
Unsorted Array: 88 52 93 69 35 21 63 47 2 17
Sorted Array: 2 17 21 35 47 52 63 69 88 93
you need to make a copy of the list
List<int> deliverList = listToSort.Select(x=>x);
Related
I have made a method that can grab all row values from a specific column in a database and cast them into a list as integers. when i ran this code on my personal computer it worked like a charm, but on my company computer this code throws an exception.
This is the code:
static void Main(string[] args)
{
int norm = 43;
List<int> List = new List<int>();
string connString = ///
DataTable dt = new DataTable();
using (OleDbConnection conn = new(connString))
{
OleDbCommand cmd = new("SELECT * FROM USERS", conn);
conn.Open();
OleDbDataAdapter adapter = new(cmd);
adapter.Fill(dt);
}
try
{
if (norm == 33)
{
for (int i = 0; i < 9; i++)
{
List.Add(Convert.ToInt32(dt.Rows[i].Field<int>(1)));
}
Console.WriteLine(LeftSegmentIndex(List, 27));
}
else if (norm == 43)
{
for (int i = 9; i < dt.Rows.Count; i++)
{
List.Add(Convert.ToInt32(dt.Rows[i].Field<int>(1)));
}
Console.WriteLine(LeftSegmentIndex(List, 27));
}
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
The code throws the following exception:
System.InvalidCastException: Unable to cast object of type 'System.Double' to type 'System.Int32'.
at System.Data.DataRowExtensions.UnboxT`1.ValueField(Object value)
at System.Data.DataRowExtensions.Field[T](DataRow row, Int32 columnIndex)
This exception occurs on line 46.
the database has numbers like this :
Soc Art T_c
12 13 11
15 17 13
18 20 16
22 24 19
25 28 23
28 32 26
32 36 30
36 39 35
44 44 44
13 14 12
16 17 14
19 21 17
22 25 21
26 29 24
30 33 28
33 37 32
37 40 36
44 44 44
Can someone please explain why this error gets thrown at my company computer but not on my personal computer?
Thanks.
The error tells you that the underlying value is double and you are trying to read it as int. If the type is different in different DBs - don't assume int, just let Convert.ToInt32 do its work:
List.Add(Convert.ToInt32(dt.Rows[i][1]));
I have a list which contains some documents (for simplicity strings). Now the list is getting populated slowly. What I want to do is when the size of the list reaches 20 I want to call another function that will print these strings asynchronously without stopping the main method. After lot of searching I have managed to put together this code
public void DoStuff()
{
Class1 p = new Class1();
List<string> list = new List<string> { };
var TList = new List<Task>();
int i = 0;
while (i < 90)
{
list.Add(i.ToString());
if (list.Count == 20)
{
Console.WriteLine("List contents when calling: " + list[0]);
TList.Add(Task.Run(() => publishDoc(list)));
list.Clear();
}
i++;
}
if (list.Count != 0)
{
TList.Add(Task.Run(() => publishDoc(list)));
}
Task.WhenAll(TList).Wait();
Console.WriteLine("Done DoStuff");
}
public async Task publishDoc(List<string> docs)
{
Console.WriteLine(iter++ + " " + docs[0]);
await Task.Run(() => Thread.Sleep(1000));
foreach (var val in docs)
{
Console.Write(val + " ");
}
Console.WriteLine();
}
This is what I am getting as output
List contents when calling: 0
List contents when calling: 20
List contents when calling: 40
List contents when calling: 60
1 80
3 80
0 80
2 80
4 80
80 80 80 80 81 82 83 84 85 86 87 88 89
81 82 83 84 85 86 87 88 89
81 82 83 84 85 86 87 88 89
81 82 83 84 85 86 87 88 89
80 81 82 83 84 85 86 87 88 89
Done DoStuff
Done Main
I can't figure out why it is only printing the last passed data i.e. why the passed list is getting overwritten.
Now if I do this
public void DoStuff()
{
Program2 p = new Program2();
List<string> list = new List<string> { };
int i = 0;
while (i < 90)
{
list.Add(i.ToString());
if (list.Count == 20)
{
Console.WriteLine("List contents when calling: " + list[0]);
var tasks = publishDoc(list);
if (tasks.Result == "Done")
{
Console.WriteLine("Done " + list[0]);
}
list.Clear();
}
i++;
}
if (list.Count != 0)
{
var tasks = publishDoc(list);
if (tasks.Result == "Done")
{
Console.WriteLine("Done " + list[0]);
}
}
Console.WriteLine("Done DoStuff");
}
public async Task<string> publishDoc(List<string> docs)
{
Console.WriteLine(iter++ + " " + docs[0]);
foreach (var val in docs)
{
Console.Write(val + " ");
}
Console.WriteLine();
return await Task.Run(() => "Done");
}
I get this output
List contents when calling: 0
0 0
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
Done 0
List contents when calling: 20
1 20
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
Done 20
List contents when calling: 40
2 40
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
Done 40
List contents when calling: 60
3 60
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
Done 60
4 80
80 81 82 83 84 85 86 87 88 89
Done 80
Done DoStuff
Done Main
This is giving the correct output but is doing it synchronously which I don't want. Please help and thanks in advance.
you have to do like this , as in loop it points to same instance of list every time that might causing issue , so I suggest you create copy of list before passing it to function publishDoc
while (i < 90)
{
list.Add(i.ToString());
if (list.Count == 20)
{
List<string> copy = list.ToList();
Console.WriteLine("List contents when calling: " + copy[0]);
TList.Add(Task.Run(() => publishDoc(copy)));
list.Clear();
}
i++;
}
Refer this answer also : Starting Tasks In foreach Loop Uses Value of Last Item
My program currently reads in the values from a text file that is in the .HRM format and will parse them depending on the column the data is contained in and insert the data into the appropriate row. The code I have currently will read in the code and below that i attempted to make the code into a list which is then inserted into the datagridview but I think I have done this incorrectly due to not having the array set up correctly as I am not sure how it would split between the columns nor how I would decide which row of the datagridview the data would be inserted into. This is the code I am using to load in the file:
namespace WindowsFormsApplication6
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
{
string filePath = #"F:\testdata.hrm";
if (File.Exists(filePath))
processfile(filePath);
else
System.Console.WriteLine("Error - File {0} not Found", filePath);
System.Console.ReadKey();
}
}
// static void processfile(String filePath)
// {
// List<string[]> result = File.ReadAllLines("filePath") //read all lines in the file
// .SkipWhile(x => x != "[HRData]") //skip lines until reaching the "[HRData]"
// .Select(x => x.Split(null, StringSplitOptions.RemoveEmptyEntries)) //split line by whitespace to get numbers in line
// .ToList(); // convert the result to a list
// result.ForEach(x => dataGridView1.Rows.Add(x));
}
}
}
This is the data I am reading in:
[HRData]
91 154 70 309 83 6451
91 154 70 309 83 6451
92 160 75 309 87 5687
94 173 80 309 87 5687
96 187 87 309 95 4662
100 190 93 309 123 4407
101 192 97 309 141 4915
103 191 98 309 145 5429
106 190 99 309 157 4662
106 187 98 309 166 4399
107 186 97 309 171 4143
107 185 97 309 170 4914
108 184 96 309 171 5426
108 183 95 309 170 5688
So what I will want to do is read each column in the file then adding each column into a seperate array for each of the columns and they will then be inserted into the datagridview in the appropriate columns. I tried to code this but I'm not sure what I did wrong so any help would be appreciated.
You can do like this:
var lines = File.ReadAllLines(#"F:\testdata.hrm").Skip(1);
foreach (var line in lines)
dataGridView1.Rows.Add(line.Split(
new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries));
EDIT:
Based on you comment, you want rotate row to column, and column to row. You can do like bellow:
var lines = File.ReadAllLines(#"F:\testdata.hrm").Skip(1);
List<string[]> list = new List<string[]>();
foreach (var line in lines)
{
list.Add(line.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries));
}
for (int i = 0; i < 6; i++)
{
List<string> cols = new List<string>();
for (int j = 0; j < list.Count; j++)
{
cols.Add(list[j][i]);
}
dataGridView1.Rows.Add(cols.ToArray());
}
To add header to a row:
List<string> rowHeaders = new List<string> { "A", "B", "C", "D", "E", "F", "G" };
for (int i = 0; i < dataGridView1.Rows.Count; i++)
{
dataGridView1.Rows[i].HeaderCell.Value = rowHeaders[i];
}
It looks like you are implementing Linq into C# code? Also, you want to separate each column into an array of itself, but you have only declared one array? If you want each column into its own array, you need to declare multiple arrays, or you need to declare a 3-D array. I would recommend using a foreach loop that this:
foreach(string column in filepath)
{
string[] result = File.ReadAllLines("filePath");
string dataColumn = dataGridView1.Rows.Add(result));
}
I tried to write simple program, that simulates lottery and I got some behavior I cannot understand, nor fix:
To keep it simple I excluded code that is irrelevant to the problem
PROGRAM: On click it should Get six different numbers (between 1 and 49) entered by user, get six different random numbers (between 1 and 49) compare them and repeat getting random numbers and comparing with entered until there are three matches.
What is relevant, I am calling function GetResults() on button click and passing to it two parameters (method definition below). I simplified it to button click to show you. There are some conditions and function calls there, but they are working and problem exists even without them so that's why image example on the bottom may be a little different.
private void btnCheck_Click(object sender, EventArgs e)
{
lotto.GetResults(3, ref listRndNumLabels);
lblMatches.Text = lotto.CurrentMatches.ToString();
lblTryCounter.Text = lotto.NumberOfTries.ToString();
lblBalance.Text = lotto.Balance.ToString() + " zł";
lblThreesAmmount.Text = lotto.ThreesAmmount.ToString();
lblFoursAmmount.Text = lotto.FoursAmmount.ToString();
lblFivesAmmount.Text = lotto.FivesAmmount.ToString();
lblSixesAmmount.Text = lotto.SixesAmmount.ToString();
}
The method GetResults() takes 3 as number of desired matches and List of Labels which is updated at the end
public void GetResults(int Choice, ref List<Label> listLblRndNum)
{
_currentMatches = 0;
int desiredNumberOfMatches = Choice;
// while we got other ammount of matches than three, go again
while (_currentMatches != desiredNumberOfMatches)
{
_numberOfTries++;
// get list of mutually exclusive 6 numbers betweeen 1 and 49
var tempList = GetRndNums();
// insert random numbers to list
_listLotteryNumbers.Clear();
for (int i = 0; i < 6; i++)
{
_listLotteryNumbers.Insert(i, tempList[i]);
}
_balance -= _ticketCost;
_currentMatches = 0;
// get number of matches
for (int i = 0; i < 6; i++)
{
foreach (int num in _listLotteryNumbers)
{
if (_listSelectedNumbers[i] == num)
{
_currentMatches++;
}
}
}
//FrmLotto.lbResults.Items.Add(_numberOfTries.ToString() + " - _currentMatches: " + _currentMatches.ToString());
//FrmLotto.lbResults.Items.Add(_numberOfTries.ToString() + " - tempList { " + tempList[0] + " " + tempList[1] + " " + tempList[2] + " " + tempList[3] + " " + tempList[4] + " " + tempList[5] + " }");
//FrmLotto.lbResults.Items.Add(_numberOfTries.ToString() + " - _listLotteryNumbers { " + _listLotteryNumbers[0] + " " + _listLotteryNumbers[1] + " " + _listLotteryNumbers[2] + " " + _listLotteryNumbers[3] + " " + _listLotteryNumbers[4] + " " + _listLotteryNumbers[5] + " }");
//FrmLotto.lbResults.Items.Add(_numberOfTries.ToString() + " - _listSelectedNumbers { " + _listSelectedNumbers[0] + " " + _listSelectedNumbers[1] + " " + _listSelectedNumbers[2] + " " + _listSelectedNumbers[3] + " " + _listSelectedNumbers[4] + " " + _listSelectedNumbers[5] + " }");
// update stats
if (_currentMatches == 3)
{
_threesAmmount++;
_balance += 10;
}
else if (_currentMatches == 4)
{
_foursAmmount++;
_balance += 100;
}
else if (_currentMatches == 5)
{
_fivesAmmount++;
_balance += 3500;
}
else if (_currentMatches == 6)
{
_sixesAmmount++;
_balance += 1000000;
}
//FrmLotto.lbResults.Items.Add(_numberOfTries.ToString() + " - Threes Ammount right after updating: " + _threesAmmount);
//FrmLotto.lbResults.Items.Add("");
// this gets out of the loop if user has chosen from ddl to run once, it is irrelevant here
if (desiredNumberOfMatches == -1)
break;
}
// finally update Labels with the desired result
for (int i = 0; i < 6; i++)
{
listLblRndNum[i].Text = _listLotteryNumbers[i].ToString();
}
}
And this is the function which gets random numbers:
public List<int> GetRndNums()
{
List<int> listRndNums = new List<int>();
Random rndNum = new Random();
for (int i = 0; i < 6; i++)
{
int myNum = 0;
do
myNum = rndNum.Next(1, 49);
while (listRndNums.Contains(myNum));
listRndNums.Add(myNum);
}
listRndNums.Sort();
return listRndNums;
}
So program works as expected if loop run once, or if there is delay after each loop, or if I put breakpoint in the loop.
OTHERWISE there is an unexpected behavior, loop run more than once for the same data (for the same lists), I don't understand why.
look at the images:
Program run once, I clicked button five times, to show you that results are fine:
(btw = Sprawdź = Check, raz = once, do pierwszej trójki = until 3 matches)
http://ultraimg.com/jHQY
And when I select until 3 matches (or click button from the code example above) I am receiving wrong result, loop runs multiple times for the same values.
http://ultraimg.com/jHQn
Would be really grateful for help, I am learning, I know that many parts of code could be improved, many parts are for temp debugging purposes only. But this behavior, I simply don't get it.
In order to fix this problem you should try making
Random rndNum = new Random();
a static variable.
See this :
http://msdn.microsoft.com/en-us/library/system.random.aspx
Pseudo-random numbers are chosen with equal probability from a finite set of numbers. The chosen numbers are not completely random because a definite mathematical algorithm is used to select them, but they are sufficiently random for practical purposes. The current implementation of the Random class is based on Donald E. Knuth's subtractive random number generator algorithm. For more information, see D. E. Knuth. "The Art of Computer Programming, volume 2: Seminumerical Algorithms". Addison-Wesley, Reading, MA, second edition, 1981.
The random number generation starts from a seed value. If the same
seed is used repeatedly, the same series of numbers is generated. One
way to produce different sequences is to make the seed value
time-dependent, thereby producing a different series with each new
instance of Random. By default, the parameterless constructor of the
Random class uses the system clock to generate its seed value, while
its parameterized constructor can take an Int32 value based on the
number of ticks in the current time. However, because the clock has
finite resolution, using the parameterless constructor to create
different Random objects in close succession creates random number
generators that produce identical sequences of random numbers. The
following example illustrates that two Random objects that are
instantiated in close succession generate an identical series of
random numbers.
byte[] bytes1 = new byte[100];
byte[] bytes2 = new byte[100];
Random rnd1 = new Random();
Random rnd2 = new Random();
rnd1.NextBytes(bytes1);
rnd2.NextBytes(bytes2);
Console.WriteLine("First Series:");
for (int ctr = bytes1.GetLowerBound(0);
ctr <= bytes1.GetUpperBound(0);
ctr++) {
Console.Write("{0, 5}", bytes1[ctr]);
if ((ctr + 1) % 10 == 0) Console.WriteLine();
}
Console.WriteLine();
Console.WriteLine("Second Series:");
for (int ctr = bytes2.GetLowerBound(0);
ctr <= bytes2.GetUpperBound(0);
ctr++) {
Console.Write("{0, 5}", bytes2[ctr]);
if ((ctr + 1) % 10 == 0) Console.WriteLine();
}
// The example displays the following output to the console:
// First Series:
// 97 129 149 54 22 208 120 105 68 177
// 113 214 30 172 74 218 116 230 89 18
// 12 112 130 105 116 180 190 200 187 120
// 7 198 233 158 58 51 50 170 98 23
// 21 1 113 74 146 245 34 255 96 24
// 232 255 23 9 167 240 255 44 194 98
// 18 175 173 204 169 171 236 127 114 23
// 167 202 132 65 253 11 254 56 214 127
// 145 191 104 163 143 7 174 224 247 73
// 52 6 231 255 5 101 83 165 160 231
//
// Second Series:
// 97 129 149 54 22 208 120 105 68 177
// 113 214 30 172 74 218 116 230 89 18
// 12 112 130 105 116 180 190 200 187 120
// 7 198 233 158 58 51 50 170 98 23
// 21 1 113 74 146 245 34 255 96 24
// 232 255 23 9 167 240 255 44 194 98
// 18 175 173 204 169 171 236 127 114 23
// 167 202 132 65 253 11 254 56 214 127
// 145 191 104 163 143 7 174 224 247 73
// 52 6 231 255 5 101 83 165 160 231
This problem can be avoided by creating a single Random object rather
than multiple ones. To improve performance, create one Random object
to generate many random numbers over time, instead of repeatedly
creating a new Random objects to generate one random number. To
generate a cryptographically secure random number suitable for
creating a random password, for example, use a class derived from
System.Security.Cryptography.RandomNumberGenerator such as
System.Security.Cryptography.RNGCryptoServiceProvider.
I want to list permutations with only 0 and 1. Similar to binary but allowing variable lengths, doesn't have to equal 8 length. For example:
0
1
00
01
10
11
000
001
010
011
100
101
110
111
All the way until the length of X is met. How can this be done?
You can also use:
using System;
class Test
{
static void permute(int len)
{
for (int i=1; i<=len; i++)
{
for (int j=0; j<Math.Pow(2, i); j++)
{
Console.WriteLine (Convert.ToString(j, 2).PadLeft(i, '0'));
}
}
}
}
Which involves no recursion :)
I would do this as a recursive call, one function to do all of a specific length, another to call that for all relevant lengths. The following complete C# 2008 console application shows what I mean:
using System;
namespace ConsoleApplication1 {
class Program {
static void permuteN(string prefix, int len) {
if (len == 0) {
System.Console.WriteLine(prefix);
return;
}
permuteN(prefix + "0", len - 1);
permuteN(prefix + "1", len - 1);
}
static void permute(int len) {
for (int i = 1; i <= len; i++)
permuteN("", i);
}
static void Main(string[] args) {
permute(3);
}
}
}
This outputs:
0
1
00
01
10
11
000
001
010
011
100
101
110
111
which is what I think you were after.