Я думаю, вы должны отделить свои проблемы .Разделяйте способ получения данных (считывание из CSV-файла), способ обработки данных (поиск наиболее популярного вхождения в первом столбце) и способ отображения даты (вставьте в элемент отображения, который вэтот случай является списком)
Разделение интересов имеет несколько преимуществ:
- Поскольку ваш код ориентирован на одну тему, он будет более понятен.
- Код будетпроще тестировать без дополнительных затрат.
- Код можно использовать повторно.Вы можете использовать чтение CSV-файла для заполнения других элементов, например таблицы
- Если одна из проблем меняется, например, вы читаете свои данные из базы данных, а не из CSV-файла, вы выиграли 'не нужно много менять код.
Вы сказали, что у вас проблема с LINQ, поэтому я думаю, у вас не будет проблем с чтением ваших входных данных.У вас будет такой код:
class Person
{
public string Name {get; set;}
public DateTime Dob {get; set;}
public bool Male {get; set;}
public int Age => (DateTime.Now - this.Dob).Years // almost correct, TODO: repair
}
IEnumerable<Person> ReadPersons() {...} // reads from your input file
Аналогично, у вас будет некоторая функция, которая добавляет человека к объекту, который показывает людей оператору.В вашем случае это ListBox, но поскольку мы разделили проблемы, нам все равно.В конце концов, вы сказали, что освоили его добавление.
void DislayName(string name) {... add name to the listbox }
Теперь все, что вам нужно сделать, это создать функцию, которая выбирает имя человека, которого вы хотите отобразить.
string SelectNameToDisplay(IEnumerable<Person> persons)
{
TODO: implement
}
private void btnPopularCourse_Click(object sender, EventArgs e)
{
IEnumerable<Person> persons = ReadPersons();
string nameToDisplay = SelectNameToDisplay(persons);
DisplayName(nameToDisplay);
}
Вы указали, что у вас не было проблем с чтением людей и отображением имени, поэтому все, что нам нужно сделать, - это выбрать правильное имя
Я добавил ... Или на всякий случай, в случаенет людей
string SelectNameToDisplayOrDefault(IEnumerable<Person> persons)
{
// TODO: exception if persons equals null
// select the person with the name that occurs most
// group them by name, and count the number of persons in each group
// finally take the group with the largest number of persons
var mostUsedName = persons
.GroupBy(person => person.Name, // KeySelector
(name, personsWithThisName) => new // ResultSelector
{
Name = name,
Count = personsWithThisName.Count(),
})
// order such that the person that occurs most comes first
.OrderByDescending(person => person.Count)
// keep only the name:
.Select(person => person.Name)
// and take the first one
.FirstOrDefault();
return mostUsedName;
}
Хотя это и выполнит работу в одном операторе LINQ, это немного трата вычислительной мощности, чтобы отсортировать всех людей по количеству, если вам нужен только один человек, который идет первымпосле сортировки.Я бы немного изменил процедуру:
string SelectNameToDisplayOrDefault(IEnumerable<Person> persons)
{
var personsWithCount = persons
.GroupBy(person => person.Name, // KeySelector
(name, personsWithThisName) => new // ResultSelector
{
Name = name,
Count = personsWithThisName.Count(),
});
// get the person that has the highest count, enumerating only once:
var personEnumerator = personsWithCount.GetEnumerator();
if (personEnumerator.MoveNext())
{
// there is at least one Person:
var mostOftenCountedPerson = personEnumerator.Current;
// check if other persons have a higher count:
while (personEnumerator.MoveNext())
{
// there is a next Person; does he have a higher Count?
if (personEnumerator.Current.Count > mostOftenCountedPerson.Count)
{
// yes this person is counted more often
mostOftenCountedPerson = personEnumerator.Current;
}
}
// enumerated the sequence exactly once, and we know the Person that is counted most
return mostOftenCountedPerson;
}
else
{
// no person at all; TODO: decide what to do
}
}