Related
A coworker and I got the task to fix an problem on a SQL-Client.
The error is a System.OutOfMemoryException.
I figured that it could be because of the client has to many connections that doesn't get closed properly.
I tested a bit around but I can't seem to get it working.
Anyone have a suggestion?
This is the code where the error happens:
public void SQLIntoDataGridView(OracleCommand cmd, int startIndex, int maxIndex, int ersteSpalte, int maxSpalten, DataTable datenTabelle, DataGridView dgv, int sqlNr, DataTable dt)
{
OracleConnection test = new OracleConnection();
int i = 0;
int j = 0;
int spalten = ersteSpalte;
int id;
int spaltenZaehler = ersteSpalte;
int maxrows = datenTabelle.Rows.Count;
int readZeile = 0;
int writeZeile = 0;
int startrow = 0;
int startSpalte = 0;
int endSpalte = 0;
Stopwatch watch = new Stopwatch();
watch.Start();
test.ConnectionString = "Data Source=; User ID=; Password=";
using (test)
{
if (test.State == ConnectionState.Closed)
test.Open(); // <-- this is where the error occures
using (OracleDataReader reader = cmd.ExecuteReader())
{
datenTabelle.Load(reader);
dataGridViewErgebnis.DataSource = dt;
dataGridViewTest.DataSource = datenTabelle;
dataGridViewErweitern(sqlNr);
#region Rechnungsempfänger X
if (startIndex == 27 || startIndex == 24)
{
while (j < dataGridViewErgebnis.Rows.Count - 1)
{
id = startIndex;
if (dataGridViewErgebnis.Rows[j].Cells[21].Value.ToString() == "")
{
readZeile++;
i = readZeile;
j++;
writeZeile++;
}
else if (dataGridView1.Rows[startrow].Cells[0].Value.ToString() == dataGridViewErgebnis.Rows[j].Cells[21].Value.ToString())
{
if (startIndex == 24)
{
startSpalte = 7;
endSpalte = 9;
spaltenZaehler = startSpalte;
}
else if (startIndex == 27)
{
startSpalte = 10;
endSpalte = 14;
spaltenZaehler = startSpalte;
}
spaltenZaehler = startSpalte;
maxSpalten = endSpalte;
while (spaltenZaehler <= maxSpalten)
{
i = startrow;
dataGridViewErgebnis.Rows[writeZeile].Cells[id].Value = dgv.Rows[i].Cells[spaltenZaehler].Value.ToString();
spaltenZaehler++;
id++;
}
readZeile++;
i = readZeile;
j++;
writeZeile++;
spaltenZaehler = startSpalte;
startrow = 0;
}
else
{
startrow++;
}
if (i == dt.Rows.Count - 1 && j == datenTabelle.Rows.Count - 1)
{
id = startIndex;
while (id <= maxIndex && spaltenZaehler <= maxSpalten)
{
dataGridViewErgebnis.Rows[writeZeile].Cells[id].Value = dataGridViewTest.Rows[i].Cells[spaltenZaehler].Value.ToString();
id++;
spaltenZaehler++;
}
}
}
}
#endregion
else
{
while (i < dt.Rows.Count - 1)
{
id = startIndex;
if (dataGridViewErgebnis.Rows[i].Cells[0].Value.ToString() == dataGridViewTest.Rows[j].Cells[0].Value.ToString())
{
while (spaltenZaehler <= maxSpalten)
{
dataGridViewErgebnis.Rows[i].Cells[id].Value = dataGridViewTest.Rows[j].Cells[spaltenZaehler].Value.ToString();
spaltenZaehler++;
id++;
}
if (startIndex == 10 && j == datenTabelle.Rows.Count - 1)
{
j--;
j--;
i++;
}
if (j <= datenTabelle.Rows.Count - 1)
{
j++;
}
spaltenZaehler = ersteSpalte;
}
else
{
i++;
while (id <= maxIndex)
{
dataGridViewErgebnis.Rows[i].Cells[id].Value = "";
id++;
}
}
if (i == dt.Rows.Count - 1 && j == datenTabelle.Rows.Count - 1)
{
id = startIndex;
while (id <= maxIndex && spaltenZaehler <= maxSpalten)
{
dataGridViewErgebnis.Rows[i].Cells[id].Value = dataGridViewTest.Rows[j].Cells[spaltenZaehler].Value.ToString();
id++;
spaltenZaehler++;
}
}
else if (j == datenTabelle.Rows.Count && startIndex != 10)
{
j--;
if (i <= dt.Rows.Count - 2)
{
i++;
}
}
}
}
watch.Stop();
StoppUhr(watch);
}
}
}
I would rewrite the code like this.
.
.
.
OracleConnection test = new OracleConnection();
.
.
.
using (OracleConnection test = new OracleConnection("Data Source=; User ID=; Password=")) // <-- SQLconnection here
{
test.Open(); // <-- Only Open connection
using (OracleDataReader reader = cmd.ExecuteReader())
{
.
.
.
}
}
I am trying to keep track of how many meals a person has given from two dates you can enter from DateTimePickers.
There are three meals a day between specific times between:
6-8AM Meal 1
12-2PM Meal 2
5-7PM Meal 3
If a person arrives after one of the specific times, they miss out on a meal, so for example if I arrive on 1 Jan 2018 3AM and leave on 2 Jan 2018 2PM I will only receive 5 meals, as I missed out on the last meal.
This is the code I have come up with, but unfortunately I struggle to work the code out if the time between the two dates are more than one day apart.
private void button1_Click(object sender, EventArgs e)
{
dateTimeExit.CustomFormat = "MM/dd/yyyy hh:mm:ss tt";
dateTimeArrive.CustomFormat = "MM/dd/yyyy hh:mm:ss tt";
DateTime timeArrived = dateTimeArrive.Value;
DateTime timeExit = dateTimeExit.Value;
int totalHoursArrived = timeArrived.Hour;
int totalHoursExit = timeExit.Hour;
int totalCounts = 0;
int countA = 0; //6-8 AM
int countB = 0; //12-2PM
int countC = 0; //5-7PM
int totalDaysLeft = (timeExit - timeArrived).Days; //determines the number of days between the two given dates.
if (totalDaysLeft == 1)
{
totalCounts = 3;
countA = 1;
countB = 1;
countC = 1;
}
else if (totalDaysLeft < 1) //difference between the two dates is less than a day.
{
totalCounts = totalDaysLeft * 3;
countA = totalDaysLeft;
countB = totalDaysLeft;
countC = totalDaysLeft;
if (timeExit.Day == timeArrived.Day) //if the dates are on the same day and "less than one day"
{
if (totalHoursArrived <= 8 && totalHoursExit >= 17) //if date is before or on 8AM and leaves on or after 5PM.
{
countA = 1;
countB = 1;
countC = 1;
}
else if (totalHoursArrived <= 8 && (totalHoursExit >= 12 && totalHoursExit < 17)) //if date is before or on 8AM and leaves before 5PM
{
countA = 1;
countB = 1;
}
else if (totalHoursArrived <= 8 && totalHoursExit < 12) //if date is before or on 8AM and leaves before 12PM
{
countA = 1;
}
else if ((totalHoursArrived <= 12 && totalHoursArrived > 8) && totalHoursExit >= 17) //if date is before or on 12PM and leaves on or after 5PM
{
countB = 1;
countC = 1;
}
else if ((totalHoursArrived <= 12 && totalHoursArrived > 8) && totalHoursExit < 17) //if date is before or on 12PM and leaves before 5PM
{
countB = 1;
}
else if (totalHoursArrived >= 17) //if date is after or on 5PM
{
countC = 1;
}
totalCounts = countA + countB + countC;
}
else //less than a day, but not on same day exit time.
{
if (totalHoursArrived <= 8) //if date is before or on 8AM.
{
totalCounts = 3;
countA = 1;
countB = 1;
countC = 1;
}
else if (totalHoursArrived >= 12 && totalHoursArrived < 17)// //if date is after or on 12PM and arrival time is less than 5PM
{
totalCounts = 2;
countB = 1;
countC = 1;
}
else if (totalHoursArrived >= 17) //if date is after or on 5PM
{
totalCounts = 1;
countC = 1;
}
if (totalHoursExit > 0) // exit time
{
if (totalHoursExit >= 17)
{
totalCounts += 3;
countA += 1;
countB += 1;
countC += 1;
}
else if (totalHoursExit >= 12 && totalHoursExit < 17)
{
totalCounts += 2;
countA += 1;
countB += 1;
}
else if (totalHoursExit >= 6 && totalHoursExit < 12)
{
totalCounts += 1;
countA += 1;
}
}
}
}
else //more than two days difference between the two dates.
{
**//the part I am struggling to figure out**
}
lblTotalCountA.Text = "Count A: " + countA;
lblTotalCountB.Text = "Count B: " + countB;
lblTotalCountC.Text = "Count C: " + countC;
lblTotalAmount.Text = "Total Counts: " + totalCounts;
}
I find your code quite difficult to mantain (if you would like to add a fourth meal in the future, it would be a nightmare to change your code), so I'm giving you a different approach, as well as answering your question.
First I would define a class like this:
public class DayMeals
{
private int[] entryTimes = new int[] { 6, 12, 17 };
private int[] exitTimes = new int[] { 8, 14, 19 };
private int[] mealCounts = new int[3];
private bool countHalfMeals = false;
public DayMeals(bool countHalfMeals)
{
this.countHalfMeals = countHalfMeals;
}
public void AddFullDay()
{
mealCounts[0]++;
mealCounts[1]++;
mealCounts[2]++;
}
public void CountMealsForADay(DateTime timeArrived, DateTime timeExit)
{
for (int i = 0; i < mealCounts.Length; i++)
{
int mealEntryTime = entryTimes[i];
int mealExitTime = exitTimes[i];
if (timeArrived.Hour <= mealEntryTime && timeExit.Hour >= mealExitTime)
mealCounts[i]++;
else if (countHalfMeals && timeExit.Hour > mealEntryTime && timeExit.Hour <= mealExitTime)
mealCounts[i]++;
}
}
public void PrintMealsCount()
{
for (int i = 0; i < mealCounts.Length; i++)
{
System.Console.WriteLine($"Meal #{i + 1} count = {mealCounts[i]}");
}
}
}
Then, I would simply instantiate the class and call the functions:
void Main(string[] args)
{
CalculateMeals(new DateTime(2019, 1, 1, 15, 12, 1), new DateTime(2019, 1, 2, 18, 0, 0));
}
public static void CalculateMeals(DateTime timeArrived, DateTime timeExit)
{
// Number of full days
int fullDaysNumber = (timeExit - timeArrived).Days;
DayMeals dayMeals = new DayMeals(true);
for (int i = 0; i <= fullDaysNumber; i++)
{
int hoursDiff = (int)(timeExit - timeArrived).TotalHours;
if (timeExit.Day > timeArrived.Day && hoursDiff > 24)
{
dayMeals.AddFullDay();
// A trick to make the cycle work the next time
// You can use a different variable if you want to keep timeArrived unchanged
timeArrived = timeArrived.AddDays(1);
}
else if (timeExit.Day < timeArrived.Day)
{
break;
}
else
{
if (timeArrived.Day != timeExit.Day)
{
dayMeals.CountMealsForADay(timeArrived, new DateTime(1,1,timeArrived.Day,23,59,59));
dayMeals.CountMealsForADay(new DateTime(1,1,timeExit.Day,0,0,1), timeExit);
}
else
{
dayMeals.CountMealsForADay(timeArrived, timeExit);
}
}
}
dayMeals.PrintMealsCount();
}
I tried this code and it seems to work as expected. Please review it and let me know if this is what you wanted to achieve.
NOTE: I know the usage of "AddDays(1)" is counterintuitive, because I am keeping the same hour of day 1 for a subsequent day. But, if you are not interested about the fact that a person entered at 11 on Monday rather than on Tuesday, the meals count is the same. Basically, I'm just traslating the entry time to the last day.
Here you go, without looping. I simplified further by only using standard c# objects. The trick is in counting full days and work with timespans.
public static void Main(string[] args)
{
DateTime timeArrived = new DateTime(2019, 1, 5, 13, 53, 0);
DateTime timeExit = new DateTime(2019, 1, 6, 8, 46, 0);
TimeSpan startMeal1 = new TimeSpan(6, 0, 0);
TimeSpan endMeal1 = new TimeSpan(8, 0, 0);
TimeSpan startMeal2 = new TimeSpan(12, 0, 0);
TimeSpan endMeal2 = new TimeSpan(14, 0, 0);
TimeSpan startMeal3 = new TimeSpan(17, 0, 0);
TimeSpan endMeal3 = new TimeSpan(19, 0, 0);
int daysDiff = (timeExit - timeArrived).Days;
int meals1Count = daysDiff;
int meals2Count = daysDiff;
int meals3Count = daysDiff;
TimeSpan timeDiff = timeExit - timeArrived - TimeSpan.FromDays(daysDiff);
if (timeArrived.TimeOfDay <= endMeal1 && (timeArrived.TimeOfDay + timeDiff) >= startMeal1) meals1Count++;
if (timeArrived.TimeOfDay <= endMeal2 && (timeArrived.TimeOfDay + timeDiff) >= startMeal2) meals2Count++;
if (timeArrived.TimeOfDay <= endMeal3 && (timeArrived.TimeOfDay + timeDiff) >= startMeal3) meals3Count++;
}
I havent checked this in VS but something like this should work. I copied your same day code, assuming its correct also:
public class MealCalculation
{
int countA, countB, countC = 0;
int total = 0;
public void Calculate()
{
var start = DateTime.Now;
var finish = DateTime.Now;
// Same Day
if (start.Date == finish.Date)
{
MealsCalculate(start.Hour, start.Hour);
}
// Next Day
else if (start.AddDays(1).Date == finish.Date)
{
MealsCalculate(start.Hour, 24);
MealsCalculate(0, finish.Hour);
}
// Great Than 1 Day
else
{
// First Day
MealsCalculate(start.Hour, 24);
// Middle Full Days
var days = NumberOfDays(start.Date, finish.Date);
countA += days;
countB += days;
countC += days;
// Finish Day
MealsCalculate(0, finish.Hour);
}
// Total
total = countA + countB + countC;
}
public int NumberOfDays(DateTime start, DateTime finish)
{
var days = 0;
while (start < finish)
{
start.AddDays(1);
days++;
}
return days - 1;
}
public void MealsCalculate(int totalHoursArrived, int totalHoursExit)
{
if (totalHoursArrived <= 8 && totalHoursExit >= 17) //if date is before or on 8AM and leaves on or after 5PM.
{
countA += 1;
countB += 1;
countC += 1;
}
else if (totalHoursArrived <= 8 && (totalHoursExit >= 12 && totalHoursExit < 17)) //if date is before or on 8AM and leaves before 5PM
{
countA += 1;
countB += 1;
}
else if (totalHoursArrived <= 8 && totalHoursExit < 12) //if date is before or on 8AM and leaves before 12PM
{
countA += 1;
}
else if ((totalHoursArrived <= 12 && totalHoursArrived > 8) && totalHoursExit >= 17) //if date is before or on 12PM and leaves on or after 5PM
{
countB += 1;
countC += 1;
}
else if ((totalHoursArrived <= 12 && totalHoursArrived > 8) && totalHoursExit < 17) //if date is before or on 12PM and leaves before 5PM
{
countB += 1;
}
else if (totalHoursArrived >= 17) //if date is after or on 5PM
{
countC += 1;
}
}
}
I am querying for report module to show a pivot table, some of the columns are dynamic, so i am creating a dictionary object to construct my object, so let say i have 1 user_applications table with around 40k records, and this table also referenced by other tables.
i do this :
//masters
var master_genders = CTX.translate_value_ms.Where(a => a.PSF_type == "SEX").OrderBy(o => o.translate_value_id).ToList();
var master_edus = CTX.education_lvl_ms.OrderBy(o => o.education_lvl_id).ToList();
var master_stats = CTX.app_status_ms.OrderBy(o => o.status_order).ToList();
var master_criteria = CTX.criteria_suggestion_templates.OrderBy(o => o.criteria_suggestion_template_id).ToList();
//
//load mapping
Dictionary<int, int> Gender_Map = new Dictionary<int, int>();
int start = 0;
foreach (var m in master_genders)
{
Gender_Map.Add(m.translate_value_id, start);
start++;
}
Dictionary<int, int> Edu_Map = new Dictionary<int, int>();
start = 0;
foreach (var e in master_edus)
{
Edu_Map.Add(e.education_lvl_id, start);
start++;
}
Dictionary<string, int> Stat_Map = new Dictionary<string, int>();
start = 0;
var first = master_stats.GroupBy(g => g.status_web).OrderBy(o => o.FirstOrDefault().status_order);
foreach (var s in first)
{
Stat_Map.Add(s.Key, start);
start++;
}
Dictionary<int, int> Criteria_Map = new Dictionary<int, int>();
start = 0;
foreach (var m in master_criteria)
{
Criteria_Map.Add(m.criteria_suggestion_template_id, start);
start++;
}
//
var idx = 0;
var cur_age = 0;
int int_jobfair = 0;
int total = 0;
user_address address_dom = null;
string key = "";
bool check = false;
ReportSubObject obj = null;
user_edu user_last_edu = null;
user_test last_test = null;
criteria_suggestion checkcrit = null;
var usertest = CTX.user_tests;
var testcriteria = CTX.criteria_suggestions;
double total_a = 0;
double total_b = 0;
double total_c = 0;
double total_d = 0;
double total_e = 0;
double total_f = 0;
var addresses = CTX.user_addresses.Where(a => a.address_type == 0).ToList();
foreach (var itm in apps.ToList())
{
var a_begin = DateTime.Now;
total = 0;
address_dom = null;
key = "";
check = false;
obj = null;
user_last_edu = null;
last_test = null;
checkcrit = null;
address_dom = addresses.Where(a => a.user_id == itm.user_id).FirstOrDefault();
var a_end = DateTime.Now;
DateTime b_begin = DateTime.Now;
DateTime b_end = DateTime.Now;
DateTime c_begin = DateTime.Now;
DateTime c_end = DateTime.Now;
DateTime d_begin = DateTime.Now;
DateTime d_end = DateTime.Now;
DateTime e_begin = DateTime.Now;
DateTime e_end = DateTime.Now;
DateTime f_begin = DateTime.Now;
DateTime f_end = DateTime.Now;
b_begin = DateTime.Now;
int_jobfair = 0;
if (itm.manager_id != null)
int_jobfair = 1;
key = int_jobfair + " - " + itm.applied_date.Value.Month + " - " + itm.posting.job_id + " - " + itm.posting.location_id + " - " + itm.posting.job_cat_id + " - " + itm.posting.office_cat_id + " - " + (address_dom != null && address_dom.state_id != null ? address_dom.state_id.ToString() : "0");
check = SubmissionObj.ContainsKey(key);
if (!check)
{
obj = new ReportSubObject();
obj.Source = (itm.manager_id != null ? "Job Fair" : "Website");
obj.Job = myTI.ToTitleCase(itm.posting.job_m.PSF_Desc.ToLower());
obj.Location = myTI.ToTitleCase(itm.posting.job_location_m.PSF_Desc.ToLower());
obj.JobCat = myTI.ToTitleCase(itm.posting.job_category_m.PSF_Desc.ToLower());
obj.OfficeCat = myTI.ToTitleCase(itm.posting.office_category_m.PSF_Desc.ToLower());
obj.ApplyProv = (address_dom != null && address_dom.state_id != null ? address_dom.state_m.state_desc : "");
obj.from = (DateTime)itm.applied_date;
obj.Total = total += 1;
#region gender
obj.KeyPairGender = new List<int>();
master_genders.ForEach(b => obj.KeyPairGender.Add(0));
if (itm.user_list.gender_id != null)
{
idx = Gender_Map[(int)itm.user_list.gender_id];
//obj.KeyPairGender[idx] = new KeyValuePair<string, int>(obj.KeyPairGender[idx].Key, obj.KeyPairGender[idx].Value + 1);
obj.KeyPairGender[idx] += 1;
}
#endregion
#region edu
obj.KeyPairEdu = new List<int>();
master_edus.ForEach(b => obj.KeyPairEdu.Add(0));
user_last_edu = itm.user_list.user_edus.OrderByDescending(o => o.edu_lvl_id).FirstOrDefault();
if (user_last_edu != null)
{
idx = Edu_Map[(int)user_last_edu.edu_lvl_id];
obj.KeyPairEdu[idx] += 1;
}
#endregion
b_end = DateTime.Now;
c_begin = DateTime.Now;
#region Age
obj.AgeRange = new int[5];
for (int i = 0; i < 5; i++)
{
obj.AgeRange[i] = 0;
}
cur_age = itm.applied_date.Value.Year - itm.user_list.birthday.Value.Year;
if (itm.user_list.birthday > ((DateTime)itm.applied_date).AddYears(-cur_age)) cur_age--;
if (cur_age >= 18 && cur_age <= 21)
obj.AgeRange[0] += 1;
else if (cur_age >= 22 && cur_age <= 24)
obj.AgeRange[1] += 1;
else if (cur_age >= 25 && cur_age <= 27)
obj.AgeRange[2] += 1;
else if (cur_age >= 28 && cur_age <= 30)
obj.AgeRange[3] += 1;
else if (cur_age > 30)
obj.AgeRange[4] += 1;
#endregion
#region appstatus
obj.KeyPairAppStat = new List<int>();
foreach (var loop in first)
{
obj.KeyPairAppStat.Add(0);
}
if (itm.app_status_id != null)
{
idx = Stat_Map[itm.app_status_m.status_web];
obj.KeyPairAppStat[idx] += 1;
}
#endregion
#region criteria
obj.KeyPairCriteria = new List<int>();
master_criteria.ForEach(b => obj.KeyPairCriteria.Add(0));
if (itm.online_test_id != null)
{
last_test = usertest.Where(a => a.user_id == itm.user_id && a.package_id == itm.online_test.package_id).OrderByDescending(o => o.date_score).FirstOrDefault();
if (last_test != null)
{
if (last_test.total_score != null)
{
checkcrit = testcriteria.Where(a => a.package_id == last_test.package_id &&
(last_test.total_score >= a.score_from && last_test.total_score <= a.score_to)
).FirstOrDefault();
if (checkcrit != null)
{
idx = Criteria_Map[(int)checkcrit.criteria_opt_id];
obj.KeyPairCriteria[idx] += 1;
}
}
}
}
#endregion
SubmissionObj.Add(key, obj);
c_end = DateTime.Now;
}
else
{
d_begin = DateTime.Now;
var tmp = SubmissionObj[key];
tmp.Total++;
if (tmp.to < itm.applied_date)
tmp.to = (DateTime)itm.applied_date;
#region gender
if (itm.user_list.gender_id != null)
{
idx = Gender_Map[(int)itm.user_list.gender_id];
tmp.KeyPairGender[idx] += 1;
}
#endregion
d_end = DateTime.Now;
e_begin = DateTime.Now;
#region edu
user_last_edu = itm.user_list.user_edus.OrderByDescending(o => o.edu_lvl_id).FirstOrDefault();
if (user_last_edu != null)
{
idx = Edu_Map[(int)user_last_edu.edu_lvl_id];
tmp.KeyPairEdu[idx] += 1;
}
#endregion
#region age
cur_age = itm.applied_date.Value.Year - itm.user_list.birthday.Value.Year;
if (itm.user_list.birthday > ((DateTime)itm.applied_date).AddYears(-cur_age)) cur_age--;
if (cur_age >= 18 && cur_age <= 21)
tmp.AgeRange[0] += 1;
else if (cur_age >= 22 && cur_age <= 24)
tmp.AgeRange[1] += 1;
else if (cur_age >= 25 && cur_age <= 27)
tmp.AgeRange[2] += 1;
else if (cur_age >= 28 && cur_age <= 30)
tmp.AgeRange[3] += 1;
else if (cur_age > 30)
tmp.AgeRange[4] += 1;
#endregion
#region appstatus
if (itm.app_status_id != null)
{
idx = Stat_Map[itm.app_status_m.status_web];
tmp.KeyPairAppStat[idx] += 1;
}
#endregion
e_end = DateTime.Now;
f_begin = DateTime.Now;
#region criteria
if (itm.online_test_id != null)
{
last_test = usertest.Where(a => a.user_id == itm.user_id && a.package_id == itm.online_test.package_id).OrderByDescending(o => o.date_score).FirstOrDefault();
if (last_test != null)
{
if (last_test.date_score != null)
{
checkcrit = testcriteria.Where(a => a.package_id == last_test.package_id &&
(last_test.total_score >= a.score_from && last_test.total_score <= a.score_to)
).FirstOrDefault();
if (checkcrit != null)
{
idx = Criteria_Map[(int)checkcrit.criteria_opt_id];
tmp.KeyPairCriteria[idx] += 1;
}
}
}
}
#endregion
f_end = DateTime.Now;
}
total_a += (a_end - a_begin).TotalSeconds;
total_b += (b_end - b_begin).TotalSeconds;
total_c += (c_end - c_begin).TotalSeconds;
total_d += (d_end - d_begin).TotalSeconds;
total_e += (e_end - e_begin).TotalSeconds;
total_f += (f_end - f_begin).TotalSeconds;
}
as u notice in above code, i have a few sub queries inside foreach loop, and i put a few variables to count which part took most time in seconds, and its true that the sub queries part took the longest, overall it took around 2 minutes for those codes to be executed, so i tried to move all sub queries outside foreach loop, i do this :
var customapp = apps.Select(x => new
{
dom_address = x.user_list.user_addresses.Where(a => a.address_type == 0).FirstOrDefault(),
manager_id = x.manager_id,
applied_date = x.applied_date,
job_id = x.posting.job_id,
job_desc = x.posting.job_m.PSF_Desc,
location_id = x.posting.location_id,
loc_desc = x.posting.job_location_m.PSF_Desc,
job_cat_id = x.posting.job_cat_id,
job_cat_desc = x.posting.job_category_m.PSF_Desc,
office_cat_id = x.posting.office_cat_id,
office_cat_desc = x.posting.office_category_m.PSF_Desc,
gender_id = x.user_list.gender_id,
birthday = x.user_list.birthday,
edu = x.user_list.user_edus.OrderByDescending(o => o.edu_lvl_id).FirstOrDefault(),
status_PSF_id = x.app_status_id,
status_from_PSF = x.app_status_m.status_web,
online_test_id = x.online_test_id,
last_test = x.user_tests.Where(a => a.user_id == x.user_id && a.package_id == x.online_test.package_id).OrderByDescending(o => o.date_score).FirstOrDefault()
});
DateTime end_z = DateTime.Now;
double total_z = (end_z - begin_z).TotalSeconds;
foreach (var itm in customapp.ToList())
{
//logic to construct my dictionary as before, but without sub queries.
}
the second code it does not improve the speed, instead it took longer than previous one, can u tell me what can i do to optimize my query?
The problem is that you are doing extra db calls for each subquery for each application.
This is how you can avoid it:
// Plain query, not doing subqueries. Unfortunately brings extra rows in memory.
var q =
from app in ctx.Applications
join s in ctx.SubObjectsOne on app.Id equals s.AppId into joinedSubObjectOne
from subObjectOne in joinedSubObjectOne.DefaultIfEmpty()
where subObjectOne.SomeProperty == 0 // additional sub object criteria
select new { app, subObjectOne };
var l = q.ToList();
// From now on objects are materialized, doing the rest in memory:
var translated =
from i in l
group i by i.app.Id into g
select new
{
app = g.First().app,
// This is expensive too, but not doing separate db requests.
SubObjectOneByMaxProperty = g.Select(i => i.subObjectOne).OrderByDescending(s => s.SomeOrder).FirstOrDefault()
};
var translatedList = translated.ToList();
You can use this approach if your sub-object counts are not very high.
If you can figure out how to compute a needed value using sql aggregates, it would be even better. For example,
subObjects.Where(..).OrderByDescencing(..).First(..) would turn into subObjects.Max(s=>s.SomeProp), if you need just a max value, not an entire object. It would compute directly in db without extra db calls.
And an even better approach would be to avoid computations at the time of building a report. You can denormalize your data slightly, for example - store the ids of needed objects in an aggregation table, and update the table when related data changes:
table aggregated_data(app_id, address_id, max_edu_lvl_id, max_score_test_id)
So let me start by saying that I'm a newbie with little to moderate knowledge about C#.
Coming to the topic: I need to make a program that is able to add/subtract very large integers. Initially, used BigInt only to find out it's not allowed. There should be a logical workaround for this? I have an idea which is using "elementary school method" where you add each digit starting from right to left.
I made a string which I split into char array and added each digit from right to left(GetUpperBound-i). But it doesn't seem to work.
My Code:
string s, s2;
char[] c_arr, c_arr2;
int i, erg;
s = "1234";
s2 = "5678";
c_arr = s.ToCharArray();
c_arr2 = s2.ToCharArray();
for (i = 0; i <= c_arr.GetUpperBound(0); i++)
{
erg = c_arr[c_arr.GetUpperBound(0)-i]+c_arr2[c_arr2.GetUpperBound(0)-i];
Console.Write(erg);
}
Console.ReadKey();
There are a few things wrong with your code for the 'elementary school method'. You don't account for carry, you're adding up ascii values rather than actual values between 0-9, and you're outputting the results in the wrong order.
The code below, whilst not very elegant, does produce the correct results:
var s1 = "12345";
var s2 = "5678";
var carry = false;
var result = String.Empty;
if(s1.Length != s2.Length)
{
var diff = Math.Abs(s1.Length - s2.Length);
if(s1.Length < s2.Length)
{
s1 = String.Join("", Enumerable.Repeat("0", diff)) + s1;
}
else
{
s2 = String.Join("", Enumerable.Repeat("0", diff)) + s2;
}
}
for(int i = s1.Length-1;i >= 0; i--)
{
var augend = Convert.ToInt32(s1.Substring(i,1));
var addend = Convert.ToInt32(s2.Substring(i,1));
var sum = augend + addend;
sum += (carry ? 1 : 0);
carry = false;
if(sum > 9)
{
carry = true;
sum -= 10;
}
result = sum.ToString() + result;
}
if(carry)
{
result = "1" + result;
}
Console.WriteLine(result);
The following program can be used to add two large numbers, I have used string builder to store the result. You can add numbers containing digits upto '2,147,483,647'.
Using System;
using System.Text;
using System.Linq;
public class Test
{
public static void Main()
{
string term1="15245142151235123512352362362352351236";
string term2="1522135123612646436143613461344";
StringBuilder sum=new StringBuilder();
int n1=term1.Length;
int n2=term2.Length;
int carry=0;
int n=(n1>n2)?n1:n2;
if(n1>n2)
term2=term2.PadLeft(n1,'0');
else
term1=term1.PadLeft(n2,'0');
for(int i=n-1;i>=0;i--)
{
int value=(carry+term1[i]-48+term2[i]-48)%10;
sum.Append(value);
carry=(carry+term1[i]-48+term2[i]-48)/10;
}
char[] c=sum.ToString().ToCharArray();
Array.Reverse(c);
Console.WriteLine(c);
}
}
string Add(string s1, string s2)
{
bool carry = false;
string result = string.Empty;
if(s1[0] != '-' && s2[0] != '-')
{
if (s1.Length < s2.Length)
s1 = s1.PadLeft(s2.Length, '0');
if(s2.Length < s1.Length)
s2 = s2.PadLeft(s1.Length, '0');
for(int i = s1.Length-1; i >= 0; i--)
{
var augend = Convert.ToInt64(s1.Substring(i,1));
var addend = Convert.ToInt64(s2.Substring(i,1));
var sum = augend + addend;
sum += (carry ? 1 : 0);
carry = false;
if(sum > 9)
{
carry = true;
sum -= 10;
}
result = sum.ToString() + result;
}
if(carry)
{
result = "1" + result;
}
}
else if(s1[0] == '-' || s2[0] == '-')
{
long sum = 0;
if(s2[0] == '-')
{
//Removing negative sign
char[] MyChar = {'-'};
string NewString = s2.TrimStart(MyChar);
s2 = NewString;
if(s2.Length < s1.Length)
s2 = s2.PadLeft(s1.Length, '0');
for (int i = s1.Length - 1; i >= 0; i--)
{
var augend = Convert.ToInt64(s1.Substring(i,1));
var addend = Convert.ToInt64(s2.Substring(i,1));
if(augend >= addend)
{
sum = augend - addend;
}
else
{
int temp = i - 1;
long numberNext = Convert.ToInt64(s1.Substring(temp,1));
//if number before is 0
while(numberNext == 0)
{
temp--;
numberNext = Convert.ToInt64(s1.Substring(temp,1));
}
//taking one from the neighbor number
int a = int.Parse(s1[temp].ToString());
a--;
StringBuilder tempString = new StringBuilder(s1);
string aString = a.ToString();
tempString[temp] = Convert.ToChar(aString);
s1 = tempString.ToString();
while(temp < i)
{
temp++;
StringBuilder copyS1 = new StringBuilder(s1);
string nine = "9";
tempString[temp] = Convert.ToChar(nine);
s1 = tempString.ToString();
}
augend += 10;
sum = augend - addend;
}
result = sum.ToString() + result;
}
//Removing the zero infront of the answer
char[] zeroChar = {'0'};
string tempResult = result.TrimStart(zeroChar);
result = tempResult;
}
}
return result;
}
string Multiply(string s1, string s2)
{
string result = string.Empty;
//For multipication
bool Negative = false;
if(s1[0] == '-' && s2[0] == '-')
Negative = false;
else if(s1[0] == '-' || s2[0] == '-')
Negative = true;
char[] minusChar = {'-'};
string NewString;
NewString = s2.TrimStart(minusChar);
s2 = NewString;
NewString = s1.TrimStart(minusChar);
s1 = NewString;
List<string> resultList = new List<string>();
for(int i = s2.Length - 1; i >= 0; i--)
{
string multiplycation = string.Empty;
for (int j = s1.Length - 1; j >= 0; j--)
{
var augend = Convert.ToInt64(s1.Substring(j,1));
var addend = Convert.ToInt64(s2.Substring(i,1));
long multiply = augend * addend;
// print(multiply);
multiplycation = multiply.ToString() + multiplycation;
}
//Adding zero at the end of the multiplication
for (int k = s2.Length - 1 - i; k > 0; k--)
{
multiplycation += "0";
}
resultList.Add(multiplycation);
}
for (int i = 1; i < resultList.Count; i++)
{
resultList[0] = Add(resultList[0],resultList[i]);
}
//Finally assigning if negative negative sign in front of the number
if(Negative)
result = resultList[0].Insert(0,"-");
else
result = resultList[0];
return result;
}
string Divide(string dividend, string divisor)
{
string result = string.Empty;
int remainder = 0;
int intNumberstoGet = divisor.Length;
int currentInt = 0;
int dividing = int.Parse(dividend.Substring(currentInt,intNumberstoGet));
int intDivisor = int.Parse(divisor);
while(currentInt < dividend.Length)
{
if(dividing == 0)
{
currentInt++;
result += "0";
}
else
{
while(dividing < intDivisor)
{
intNumberstoGet++;
dividing = int.Parse(dividend.Substring(currentInt,intNumberstoGet));
}
if (dividing > 0)
{
remainder = dividing % intDivisor;
result += ((dividing - remainder) / intDivisor).ToString();
intNumberstoGet = 1;
if(currentInt < dividend.Length - 2)
currentInt += 2;
else
currentInt++;
if(currentInt != dividend.Length)
{
dividing = int.Parse(dividend.Substring(currentInt,intNumberstoGet));
remainder *= 10;
dividing += remainder;
}
}
}
}
return result;
}
Here you go. Another example. It's 10 to 30 times faster than the accepted answer.
static string AddNumStr(string v1, string v2)
{
var v1Len = v1.Length;
var v2Len = v2.Length;
var count = Math.Max(v1Len, v2Len);
var answ = new char[count + 1];
while (count >= 0) answ[count--] = (char)((v1Len > 0 ? v1[--v1Len] & 0xF:0) + (v2Len>0 ? v2[--v2Len]&0xF : 0));
for (var i = answ.Length - 1; i >= 0; i--)
{
if (answ[i] > 9)
{
answ[i - 1]++;
answ[i] -= (char)10;
}
answ[i] = (char)(answ[i] | 48);
}
return new string(answ).TrimStart('0');
}
Below SO question has some interesting approaches. Though the answer is in Java, but you will surely get to know what needs to be done.
How to handle very large numbers in Java without using java.math.BigInteger
public static int[] addTwoNumbers(string s1, string s2)
{
char[] num1 = s1.ToCharArray();
char[] num2 = s2.ToCharArray();
int sum = 0;
int carry = 0;
int size = (s1.Length > s2.Length) ? s1.Length + 1 : s2.Length + 1;
int[] result = new int[size];
int index = size - 1;
int num1index = num1.Length - 1;
int num2index = num2.Length - 1;
while (true)
{
if (num1index >= 0 && num2index >= 0)
{
sum = (num1[num1index]-'0') + (num2[num2index]-'0') + carry;
}
else if(num1index< 0 && num2index >= 0)
{
sum = (num2[num2index]-'0') + carry;
}
else if (num1index >= 0 && num2index < 0)
{
sum = (num1[num1index]-'0') + carry;
}
else { break; }
carry = sum /10;
result[index] = sum % 10;
index--;
num1index--;
num2index--;
}
if(carry>0)
{
result[index] = carry;
}
return result;
}
I'm having multiple problems with my program (C#.NET) and have no idea what's causing them.
The program is intended to sort a list of names and birthdays (formatted first name,last name,DD/MM/YYYY) in ascending and descending order by first name, last name, and birthday. It is also to have other functions which have not yet been implemented.
The first problem is in the quikSortStr method. The program crashes in the first if block, stating that j is out of the bounds of the array. This happens whether or not mode == "asc".
The second, and more confusing problem is that when the values are loaded from a text file, every odd-indexed value of first and last will be null, while each odd-indexed value of bDay will be 1/1/0001.
I've included the full program below for reference, a quicksort method and the use of parallel arrays are required. My apologies for the lack of comments.
Thanks in advance for any help. I'm completely stumped.
namespace Names_Arrays
{
public partial class frmNamArrays : Form
{
System.Globalization.CultureInfo culture = new System.Globalization.CultureInfo("en-CA");
string[] first;
string[] last;
DateTime[] bDay;
string order = "asc";
string format = "d/M/yyyy";
public frmNamArrays()
{
InitializeComponent();
}
private void write()
{
string[] lines = new string[first.Length];
for (int i = 0; i < lines.Length; i++)
lines[i] = first[i] + ',' + last[i] + ',' + bDay[i].ToString(format);
txtbxNames.Clear();
txtbxNames.Lines = lines;
}
private void load()
{
string[] lines = txtbxNames.Lines;
first = new string[lines.Length];
last = new string[lines.Length];
bDay = new DateTime[lines.Length];
int i = 0;
foreach (string line in lines)
{
string[] data = line.Split(',');
//There aren't any lines that split to a string[] of length less than three,
//but for some reason the program kept believing there are.
//patched that leak.
if (data.Length == 3)
{
first[i] = data[0];
last[i] = data[1];
bDay[i] = Convert.ToDateTime(data[2], culture);
}
i++;
}
}
public DateTime[] quikSortTim(DateTime[] primary, string mode, int left, int right)
{
if (primary.Length > 1)
{
int i = left, j = right;
DateTime pivot = primary[left + (right - left) / 2];
while (i <= j)
{
if (mode == "asc")
{
while (DateTime.Compare(primary[i], pivot) < 0)
i++;
while (DateTime.Compare(primary[j], pivot) > 0)
j--;
}
else
{
while (DateTime.Compare(primary[i], pivot) > 0)
i++;
while (DateTime.Compare(primary[j], pivot) < 0)
j--;
}
if (i <= j)
{
DateTime holdoverB = primary[i];
primary[i++] = primary[j];
primary[j--] = holdoverB;
string holdover = last[i - 1];
last[i] = last[j + 1];
last[j] = holdover;
holdover = first[i - 1];
first[i] = first[j + 1];
first[j] = holdover;
}
}
if (j > left)
primary = quikSortTim(primary, mode, left, j);
if (i < right)
primary = quikSortTim(primary, mode, i, right);
}
return primary;
}
public string[] quikSortStr(string[] primary, string type, string mode, int left, int right)
{
if (primary.Length > 1)
{
int i = left, j = right;
string pivot = primary[left + (right - left) / 2];
while (i <= j)
{
if (mode == "asc")
{
while (String.Compare(primary[i], pivot) < 0)
i++;
while (String.Compare(primary[j], pivot) > 0)
j--;
}
else
{
while (String.Compare(primary[i], pivot) > 0)
i++;
while (String.Compare(primary[j], pivot) < 0)
j--;
}
if (i <= j)
{
string holdover = primary[i];
primary[i] = primary[j];
primary[j] = holdover;
if (type == "first")
{
holdover = last[i];
last[i] = last[j];
last[j] = holdover;
}
else
{
holdover = first[i];
first[i] = first[j];
first[j] = holdover;
}
DateTime holdoverBeta = bDay[i];
bDay[i] = bDay[j];
bDay[j] = holdoverBeta;
i++;
j++;
}
}
if (j > left)
primary = quikSortStr(primary, type, mode, left, j);
if (i < right)
primary = quikSortStr(primary, type, mode, i, right);
}
return primary;
}
private void frmNamArrays_SizeChanged(object sender, EventArgs e)
{
txtbxNames.Width = this.Width - 40;
txtbxNames.Height = this.Height - 157;
}
private void btnSort_Click(object sender, EventArgs e)
{
load();
switch (cbobxCategory.Text)
{
case ("First Name"):
first = quikSortStr(first, "first", order, 0, first.Length - 1);
break;
case ("Last Name"):
last = quikSortStr(last, "last", order, 0, last.Length - 1);
break;
case ("Birthday"):
bDay = quikSortTim(bDay, order, 0, bDay.Length - 1);
break;
default:
break;
}
write();
}
private void cbobxOrder_SelectedIndexChanged(object sender, EventArgs e)
{
if (cbobxOrder.Text == "Ascending")
order = "asc";
else
order = "desc";
}
private void displayfile(string name)
{
StreamReader fileData = new StreamReader(name);
txtbxNames.Lines = fileData.ReadToEnd().Split('\n');
}
private void mnuOpen_Click(object sender, EventArgs e)
{
OpenFileDialog open = new OpenFileDialog();
open.Filter = "Text Files|*.txt";
open.Title = "Select a text file...";
if (open.ShowDialog() == DialogResult.OK && open.FileName != "")
displayfile(open.FileName);
}
private void mnuExit_Click(object sender, EventArgs e)
{
this.Close();
}
}
}
You have to change the code as below in the quikSortStr method inside the if (i <= j) loop
DateTime holdoverBeta = bDay[i];
bDay[i] = bDay[j];
bDay[j] = holdoverBeta;
i++;
j--;//was: j++;
and this will fix the issue.
Thanks to saravanan for pointing out my first mistake. The out of range error was caused by an accidental incrementation of j in the wrong direction. The fixed methods are
public DateTime[] quikSortTim(DateTime[] primary, string mode, int left, int right)
{
if (primary.Length > 1)
{
int i = left, j = right;
DateTime pivot = primary[left + (right - left) / 2];
while (i <= j)
{
if (mode == "asc")
{
while (DateTime.Compare(primary[i], pivot) < 0)
i++;
while (DateTime.Compare(primary[j], pivot) > 0)
j--;
}
else
{
while (DateTime.Compare(primary[i], pivot) > 0)
i++;
while (DateTime.Compare(primary[j], pivot) < 0)
j--;
}
if (i <= j)
{
DateTime holdoverB = primary[i];
primary[i] = primary[j];
primary[j] = holdoverB;
string holdover = last[i];
last[i] = last[j];
last[j] = holdover;
holdover = first[i];
first[i] = first[j];
first[j] = holdover;
i++;
j--;
}
}
if (j > left)
primary = quikSortTim(primary, mode, left, j);
if (i < right)
primary = quikSortTim(primary, mode, i, right);
}
return primary;
}
public string[] quikSortStr(string[] primary, string type, string mode, int left, int right)
{
if (primary.Length > 1)
{
int i = left, j = right;
string pivot = primary[left + (right - left) / 2];
while (i <= j)
{
if (mode == "asc")
{
while (String.Compare(primary[i], pivot) < 0)
i++;
while (String.Compare(primary[j], pivot) > 0)
j--;
}
else
{
while (String.Compare(primary[i], pivot) > 0)
i++;
while (String.Compare(primary[j], pivot) < 0)
j--;
}
if (i <= j)
{
string holdover = primary[i];
primary[i] = primary[j];
primary[j] = holdover;
if (type == "first")
{
holdover = last[i];
last[i] = last[j];
last[j] = holdover;
}
else
{
holdover = first[i];
first[i] = first[j];
first[j] = holdover;
}
DateTime holdoverBeta = bDay[i];
bDay[i] = bDay[j];
bDay[j] = holdoverBeta;
i++;
j--;
}
}
if (j > left)
primary = quikSortStr(primary, type, mode, left, j);
if (i < right)
primary = quikSortStr(primary, type, mode, i, right);
}
return primary;
}
I did not find a solution for the second issue per se. I did, however, discover that all of the elements that read ",,1/1/0001" were added, and did not replace any names. Using this, I added to the array lines only the index values that did not contain "1/1/0001". I then used lines = lines.Where(s => s != null).ToArray(); to shorten lines by eliminating all of the now null-type values. The modified function is below.
private void write()
{
string[] lines = new string[first.Length];
for (int i = 0; i < lines.Length; i++)
if (bDay[i].ToString(format) != "1/1/0001")
lines[i] = first[i] + ',' + last[i] + ',' + bDay[i].ToString(format);
lines = lines.Where(s => s != null).ToArray();
txtbxNames.Clear();
txtbxNames.Lines = lines;
}
Thanks for the help. I found the resource for my solution here.
EDIT: It seems the problem is inherent in StreamReader.ReadToEnd(). I'm not sure why, but it can be completely avoided by using System.IO.File.ReadAllLines(filepath). In the original code, I would replace
StreamReader file = new StreamReader(name);
lines = file.ReadToEnd().Split('\n');
with
lines = File.ReadAllLines(name);
and add using System.IO;.