Calculate total average in listbox from another listbox - c#

I have these values in my listbox (above the left listbox you see the headers of the table, but this is in Dutch):
In the listbox on the right you see: employeeid, questionid and score. In the listbox on the right I want the total average score of every employeeid, by a press on a button. I need to make a algorithm, that takes the correct values of the listbox.
How can I do this? I don't know how I can say that I only want certain values from the listbox (employeeid and score, and not questionid).
I'm using a class to load in the data:
public List<ScoreMdw> GetScoreMdwList()
{
List<ScoreMdw> scoremdwList = new List<ScoreMdw>();
conn.Open();
string query = ("Select employeeid, questionid, score from contentment");
SqlCommand cmd = new SqlCommand(query, conn);
try
{
using (SqlDataReader dr = cmd.ExecuteReader())
{
while (dr.Read())
{
ScoreMdw sm = new ScoreMdw((int)dr["employeeid"], (int)dr["questionid"], (int)dr["score"]);
scoremdwList.Add(sm);
}
}
}
catch (Exception ex)
{
Exception error = new Exception("error", ex);
throw error;
}
finally
{
conn.Close();
}
return scoremdwList;
}
In the while loop I'm using an other class:
class ScoreMdw
{
private int employeeid;
private int questionid;
private int score;
public ScoreMdw(int nr, int id, int s)
{
this.employeeid= nr;
this.questionid= id;
this.score = s;
}
public int EmployeeId
{
get { return employeeid; }
}
public int QuestionId
{
get { return questionid; }
}
public int Score
{
get { return score; }
}
public override string ToString()
{
string s = string.Format("{0} \t{1} \t{2}", this.employeeid, this.questionid, this.score);
return s;
}
}
In my main window I'm doing this:
private void btnLoadScores_Click(object sender, RoutedEventArgs e)
{
scoremdwList = new List<ScoreMdw>();
try
{
conn.Open();
List<string> headers = so.GetContentmentHeaders();
foreach (string header in headers)
txtHeader.Text += header + "\t";
scoremdwList = so.GetScoreMdwList();
lbScores.ItemsSource = scoremdwList;
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
conn.Close();
}
}

You need a linq query to sum up score of same employee id like
lbScores.ItemsSource = (from e in scoremdwList
group e by e.EmployeeId into grp
select new
{
EmployeeId = grp.Key,
TotalScore = grp.Sum(a => a.Score)
}).ToList();
Where EmployeeId and TotalScore are the columns of target listbox

// string: employeeid - first int: total score - second int: number of questions
Dictionary<string, Tuple<int, int>> results = new Dictionary<string, Tuple<int, int>>();
foreach (ListViewItem item in lstvwSource.Items)
{
// check if employeeid is in Dictionary
if (results.ContainsKey(item.Text))
{
// if employeeid exists in dictionary
// add currnet score to total score
// and add one to number of questions
results[item.Text] = new Tuple<int, int>(Convert.ToInt32(item.SubItems[1].Text) + results[item.Text].Item1, +results[item.Text].Item2 + 1);
}
else
{
// if employeeid does not exist in dictionary
// add employeeid , score of the question
// set number of questions to 1
Tuple<int, int> tuple = new Tuple<int, int>(Convert.ToInt32(item.SubItems[1].Text), 1);
results.Add(item.Text, tuple);
}
}
//
lstvwDest.Items.Clear();
foreach (var result in results)
{
ListViewItem newItem = new ListViewItem();
newItem.Text = result.Key; // employeeid
newItem.SubItems.Add(result.Value.Item1.ToString()); // total score
double avg = (double)result.Value.Item1 / (double)result.Value.Item2;
newItem.SubItems.Add(avg.ToString()); // average score
lstvwDest.Items.Add(newItem);
}

Related

Trying to compare class fields C#

Below I have the constructors of two classes. Student and Course
I am trying to compare the value of _completedCourses value from the Student class against the coursecode of the Course class.
_completedCourses is a dictionary of Courses and their grades. I am trying to find which course is not completed and print that list.
Am I going about this correct.
public Course(string coursName, string courseCode, char passingGrade, double noOfCredits, Semester semesterOfferd, int major)
{
this.CourseName = coursName;
this.CourseCode = courseCode;
this.PassingGrade = passingGrade;
this.NoOfCredits = noOfCredits;
this.SemesterOfferd = semesterOfferd;
this.prerequisiteCourses = new List<Course>();
this._enrolledStudents = new List<Student>();
this._major = major;
}
public Student(int studentID, string studentName, Status studentStatus, StudentMajor studentMajor)
{
this._studentID = studentID;
this._studentName = studentName;
this._studentStatus = studentStatus;
this._studentMajor = studentMajor;
this._course = new Course();
this._completedCourses = new Dictionary<string, char>();
countStudent++;
}
public void RemainingCourses()
{
var cKey = _completedCourses.ContainsKey(_course.CourseCode);
Console.WriteLine("Remaining Courses");
if (cKey.Equals(_course.CourseCode))
{
foreach (KeyValuePair<string, char> count in _completedCourses)
{
{
{
Console.WriteLine(count.Key + " " + count.Value);
// Console.WriteLine("Course " + count.Value);
count.ToString();
}
}
}
}
}
UPDATE!!!
The following line of code in my driver class achieves what I want
Console.WriteLine("Enter Student ID ");
input = Convert.ToInt32(Console.ReadLine());
Console.Clear();
if (input.Equals(id.StudentID)) {
id.DisplayCompletedCourse();
foreach (var sub in isdCourses) {
var cKey = id.CompletedCourses.ContainsKey(sub.CourseCode);
if (!cKey)
{
Console.WriteLine(sub.CourseCode);
}
}
}
The ContainsKey method returns a boolean value (true/false), so in your if condition:
if (cKey.Equals(_course.CourseCode))
cKey is a boolean but _course.CourseCode is a string, so this will never be true, thus this will never go within the if block.
Try to rewrite it like this:
public void RemainingCourses()
{
var cKey = _completedCourses.ContainsKey(_course.CourseCode);
Console.WriteLine("Remaining Courses");
if (cKey) // if cKey is "true", then the dictionary contains the CourseCode
{
foreach (KeyValuePair<string, char> count in _completedCourses)
{
Console.WriteLine(count.Key + " " + count.Value);
}
}
}
As a side note, please beware of the formatting, you are adding unnecessary curly braces. Also, this could be simplified with linq, but I kept it as close as possible to the original code.

How to make each element of multiple lists appear on DataGrid in a single line

I have a web crawler that takes data from an airlines website.
And I want the program to display each of the elements in their respective lines.
foreach (string url in urlList)
{
driver.Navigate().GoToUrl(url);
try
{
var DepAirport = driver.FindElementsByXPath("//td[#class='depdest']/div[#class='content']").ToList();
var ArrAirport = driver.FindElementsByXPath("//td[#class='arrdest']/div[#class='content']").ToList();
var DepTime = driver.FindElementsByXPath("//td[#class='depdest']/div[#class='content emphasize']").ToList();
var ArrTime = driver.FindElementsByXPath("//td[#class='arrdest']/div[#class='content emphasize']").ToList();
var Price = driver.FindElementsByXPath("//td[#class='fareselect standardlowfare']/div[#class='content']/label[#class='label seatsokfare']").ToList();
foreach(var da in DepAirport)
{
_entries.Add(new EntryModel { DepartureAirport = da.Text });
}
foreach (var aa in ArrAirport)
{
_entries.Add(new EntryModel { ArrivalAirport = aa.Text });
}
foreach (var dt in DepTime)
{
_entries.Add(new EntryModel { DepartureTime = dt.Text });
}
foreach (var at in ArrTime)
{
_entries.Add(new EntryModel { ArrivalTime = at.Text });
}
foreach (var p in Price)
{
_entries.Add(new EntryModel { Price = p.Text });
}
}
catch (Exception e)
{
}
It collects the data and displays it on the Grid, however the results look like this:
You need to set all EntryModel properties. Like this:
for (var i = 0; i < DepAirport.Count; i++)
{
_entries.Add(new EntryModel
{
DepartureAirport = DepAirport[i].Text,
ArrivalAirport = ArrAirport[i].Text,
DepartureTime = DepTime[i].Text,
ArrivalTime = ArrTime[i].Text,
Price = Price[i].Text
});
}
The problem is that every call to _entries.Add(.. creates a new entry and, therefore, a new row. But, each row has only one property set.

Getting only values using a key from my dictonary that contians a list of values per key

Question is how can I get only the values from my dictionary that contains one key but has a list of values assigned to it. I want to be able to grab all of the values and convert them into a tuple. Any help would be greatly appreciated.
Main code
private static Dictionary<string, List<string>> v_dict_info = new Dictionary<string, List<string>>();
public static Dictionary<string, List<string>> V_dict_info
{
get => v_dict_info;
set => v_dict_info = value;
}
public static string Vista_con_s
{
get => _vista_con_s;
set => _vista_con_s = value;
}
public void get_emp_info_addr()
{
string info_addr = "select " +
"c.empno " +
"from " +
"[V4].[dbo].[person] c ";
try
{
vista_conn = new SqlConnection();
vista_conn.ConnectionString = _vista_con_s;
vista_command = new SqlCommand(info_addr, vista_conn);
vista_conn.Open();
vista_reader = vista_command.ExecuteReader();
if (vista_reader.HasRows)
{
while (vista_reader.Read())
{
v_dict_info.Vista_addr_list("empno", vista_reader.GetValue(0).ToString());
}
}
}
catch (SqlException sq_x)
{
System.Diagnostics.Debug.WriteLine("Error connecting to the database! -Error Msg: {0}", sq_x.ToString());
}
var count = v_dict_info["empno"].Count;
for (int i = 0; i < count; i++)
{
var empno = v_dict_info["empno"][i];
Console.WriteLine("{0}", empno);
}
// how can I get only the values associated to "empno" key
var xx = empno //this only return the first element :( I want all of them
Console.WriteLine(xx.ToString());
}
Here is my method for adding multiple values to one key in a dictionary.
public static class Multi_dict
{
public static void Vista_addr_list<T, U>(this IDictionary<T, List<U>> dict, T key, U elementToList)
{
List<U> list;
bool exists = dict.TryGetValue(key, out list);
if (exists)
{
dict[key].Add(elementToList);
}
else
{
dict[key] = new List<U>();
dict[key].Add(elementToList);
}
}
Presuming this is really necessary (and I agree with Gusman's comment on the question - I don't think this is really what you need), you're already half-way there.
Access the list via the key, and then select out your tuple:
dict[key].Select(x => new Tuple<string, string>(key, x));
You can find a working fiddle here: https://dotnetfiddle.net/jPX0bU

C# Filter DataGridView with the Values of Array

i want to know how i can search with the BindinSource.Filter. I have my Code like this Suche.Filter = string.Format("{0} = '{1}'", "ID", ergebnis); ergebnis is my Array with all the ID's of my Contacts. Now i want to Show all Contacts with the same ID in the DGV
This is how I solved it:
private void filter(int selectedID) {
DataTable dtFilter = new DataTable();
//speichere GridView zum Filtern
dtFilter = (DataTable)this.grdMDT.DataSource;
try {
dtFilter = dtFilter.Select("ID = " + selectedID).CopyToDataTable();
this.DGV.DataSource = dtFilter;
}
catch (Exception ex) {
MessageBox.Show(ex.Message);
}
}
I simply copy the contents of the DataGridViewto a new DataTable and use Select to get all the results I need. I then set a new DataSource for the GridView.
You may want to store the original contents of the GridView in a seperate DataTable to clear the filter results.
Of course, you'd need to do this outside of the for-loop.
I found a result for my Code, thanks Guys!
try
{
int[] ergebnis = new int[20];
var filterString = new List<string>();
for (int i = 1; i < result.Length; i++)
{
int j = Int32.Parse(result[i][12]);
ergebnis[i] = j;
filterString.Add(string.Format("{0} = '{1}'", "ID", j));
}
Suche.Filter = string.Join(" OR ", filterString);
kitba();
}
catch (IndexOutOfRangeException ex)
{
Debug.WriteLine(ex);
}
You can apply a filter by getting the view and making your array an array of objects
ICollectionView view = CollectionViewSource.GetDefaultView(yourdatagridview);
view.Filter = FilterPerItem;
yourdatagridview.ItemsSource = view;
In FilterPerItem you add the filter logic
private bool FilterPerItem(Contact item)
{
int rightID = 1;
if (item.ID == rightID)
{
return true;
}
else return false;
}

How to add a new item button to a dropdownlist using c# for Winforms API

I have a dropdown list and I populate it programmatically with a dataset pulled from a database.
What I like to do is add an option to act like a button " " button. when it is clicked a user is navigated to a different form.
something like this
(screenshot before clicking on the drop-down menu)
(screenshot to show the option like a button " "
This is the code that I am using to populate the menu
private void InventoryAdd_Load(object sender, EventArgs e)
{
InputDepartment.Items.Clear();
InputVendors.Items.Clear();
//populate the Departments menu
dbConnetion db = new dbConnetion();
string sql = " SELECT departmentName, departmentID "
+ " FROM departments "
+ " WHERE status = 'active' ";
InputDepartment.Items.Clear();
var deptSource = new List<ComboItem>();
deptSource.Add(new ComboItem { ID = -1, Text = "Select a Department" });
deptSource.Add(new ComboItem { ID = 0, Text = " < Add New> " });
foreach (var item in db.getData(sql, null, r => new ComboItem()
{
ID = Convert.ToInt32(r["departmentID"]),
Text = r["departmentName"].ToString()
})
)
{
deptSource.Add(item);
};
InputDepartment.DataSource = deptSource;
}
//This generic class will help setting an id and a text for a comboItem
class ComboItem
{
public int ID { get; set; }
public string Text { get; set; }
public string Val1 { get; set; }
public override string ToString()
{
return Text;
}
}
This is my getData Method
// query the data base
public IEnumerable<T> getData<T>(string query, List<MySqlParameter> pars, Func<IDataRecord, T> transform)
{
using (var conn = new MySqlConnection(conn_string))
using (var cmd = new MySqlCommand(query, conn))
{
if (pars != null)
{
foreach (MySqlParameter p in pars)
{
cmd.Parameters.Add(p);
}
}
conn.Open();
using (var rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
yield return transform(rdr);
}
}
conn.Close();
}
}
Instead of
deptSource.Add(new ComboItem { ID = i.ID, Text = i.Text });
use
deptSource.Add(i);
as i already is a ComboItem. Also, if your getData returns IEnumerable, that might be costly, so use.
foreach (var i in db.getData(sql, null, r => new ComboItem()
{
ID = Convert.ToInt32(r["departmentID"]),
Text = r["departmentName"].ToString()
}).ToList()
or even simpler:
deptSource.AddRange( db.getData(sql, null, r => new ComboItem()
{
ID = Convert.ToInt32(r["departmentID"]),
Text = r["departmentName"].ToString()
}) );
Finally, you need to hook up an event to:
protected override void OnSelectedValueChanged( EventArgs e )
Then you can check if the new value is 0 and perform your new item addition elsewhere.
UPDATE
I don't believe the standard ComboBox supports adding a button. There are 3rd party tools, which do. WPF also does.

Categories

Resources