Использование LINQ для упорядочения или сортировки списка и вывода в список - PullRequest
0 голосов
/ 14 февраля 2019

Я пытаюсь разделить текстовый файл на 4 столбца (через запятую) и прочитать его с помощью Streamreader, а затем найти наиболее популярное вхождение первого столбца и вывести его в список.

IЯ попробовал предложения LINQ в Интернете, но я думаю, что проблема заключается в чтении текстового файла и в формате, в котором он находится, когда я пытаюсь его отсортировать.

У меня есть список мест, и я хочу, чтобы это произошлобольшинство в списке.Когда я просто выводю неупорядоченный список, он выводится в список.

Ошибка, которую я получаю, заключается в том, что '' char 'не имеет определения для' col '?

Входной файл дляНапример:
Имя, Возраст, DOB, Мужской
Анна, 28,01 / 01/1991, Ложь
Анна, 29,06 / 06/1989, Ложь
Джон, 18,06 / 07/ 2000, True

И я хочу вывести: 'Anne' в список:

private void btnPopularCourse_Click(object sender, EventArgs e)
{
            StreamReader sr = new StreamReader(@"R:\Data.txt");
            string line = string.Empty;

            while ((line = sr.ReadLine()) != null)
            {

                lstMostPopularCourse.ClearSelected();
                string[] col = line.Split(',');

                var sort = line.GroupBy(item => item.col[0]);

                var popular = sort.OrderByDescending(group => group.Count());

                lstMostPopularCourse.Items.Add(popular.First());


            }

            sr.Close();
}


private void btnPopularCourse_Click(object sender, EventArgs e)
{
            StreamReader sr = new StreamReader(@"R:\Data.txt");
            string line = string.Empty;

            while ((line = sr.ReadLine()) != null)
            {

                lstMostPopularCourse.ClearSelected();
                string[] col = line.Split(',');

                var popular = (from item in col[0]
                group item by item into gr
                orderby gr.Count() descending
                select gr.Key).First();

                lstMostPopularCourse.Items.Add(popular);

            }

           sr.Close();
}

Ответы [ 2 ]

0 голосов
/ 14 февраля 2019

Я думаю, вы должны отделить свои проблемы .Разделяйте способ получения данных (считывание из 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
    }
}
0 голосов
/ 14 февраля 2019

Я думаю, это то, что вы ищете

static void Main(string[] args)
{
    var nameList = new List<string>();
    foreach (string line in File.ReadLines(@"YOUR PATH"))
    {
        var data = line.Split(',');
        nameList.Add(data[0]);
    }

    var mostFrequentName = nameList.GroupBy(x => x)
        .Where(g => g.Count() > 1)
        .OrderByDescending(g => g.Count())
        .Select(g => g.Key)
        .FirstOrDefault();
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...