WedX - журнал о программировании и компьютерных науках

Сумма столбцов в ListView WPF

У меня есть следующий CSV-файл:

Name,Score
Kelly,5
James,5
Sara,1
Kelly,4
James,1
John,3

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

Для начала я смог прочитать файл CSV и загрузить его в два списка для каждого столбца. ниже мой код:

   public MainWindow()
    {
        InitializeComponent();      
        using (var fs = File.OpenRead(filepath))
        using (var reader = new StreamReader(fs))
        {
            List<string> list0 = new List<string>();
            List<string> list1 = new List<string>();
            while (!reader.EndOfStream)
            {
                var line = reader.ReadLine();
                var values = line.Split(',');

                list0.Add(values[0]);
                list1.Add(values[1]);
                 //sum = list1.Sum(x => Convert.ToInt32(x));
            }

            List0.ItemsSource = list0;
            List1.ItemsSource = list1; 

         }
  }

и вот код xaml, который я использовал:

    <ListView Name="List0" HorizontalAlignment="Left" Height="258" Margin="0,33,0,0" VerticalAlignment="Top" Width="267" >
            <ListView.View>
                <GridView>
                    <GridViewColumn DisplayMemberBinding="{Binding}"/>
                </GridView>
            </ListView.View>
        </ListView>
        <ListView Name="List1" HorizontalAlignment="Left" Height="258"   Margin="272,33,0,0" VerticalAlignment="Top" Width="172" >
            <ListView.View>
                <GridView>
                    <GridViewColumn DisplayMemberBinding="{Binding}"/>
                </GridView>
            </ListView.View>
        </ListView>

И это у меня нормально работает. Но я застрял здесь, и мне было интересно, можно ли получить сумму столбца Score на основе имен в списке.

Например, получить общий балл Келли, получить общий балл Джеймса и т. д. Итак, список будет выглядеть так:

Name,Score
Kelly,9 
James,6 
Sara,1
John,3

Я попытался использовать параметр «Сумма» и подумал напечатать его на этикетке для проверки, но это не сработало, и я получил сообщение об ошибке «Входная строка была в неправильном формате».

Я все еще не очень разбираюсь в C#, WPF и XAML; особенно при чтении и анализе файлов CSV, поэтому я не уверен, как это сделать. Любая помощь в этом вопросе или указатели очень ценятся! Благодарю вас!

15.03.2017

Ответы:


1

Я бы создал новый класс для хранения людей, включая их счет. Что-то вроде этого

public class Person
{
    public string Name { get; private set; }
    public int Score { get; set; }

    public Person(string name, int score)
    {
        Name = name;
        Score = Score;
    }
}

Затем вы можете изменить свою логику на что-то вроде этого

var lines = File.ReadAllLines(filepath);
var persons = new List<Person>();

foreach(var line in lines)
{
    var values = line.Split(',');
    var name = values[0];
    var score = int.Parse(line[1].ToString());

    var person = persons.FirstOrDefault(x => x.Name == name);
    if(person == null)
    {
        var newPerson = new Person(name, score);
        persons.Add(newPerson);
    }
    else
    {
        person.Score += score;
    }
}

Преимущество класса Person — более чистый и понятный код; никаких волшебных строк, где никто не знает, что означает их значение.

В вашей логике вы можете повысить оценку человека, когда у вас уже есть одна запись для человека в вашем списке.

//редактировать привязку к xaml Например, вы можете использовать DataGrid.

<DataGrid ItemsSource="{Binding Persons}" />

Persons — это ObservableCollection<Person> в вашей ViewModel. DataGrid автоматически создаст один столбец для каждого свойства в вашем классе Person. Вы можете настроить свой DataGrid, чтобы получить желаемый вид. В инете много примеров.

//edit Binding Коллекция с лицами должна быть общедоступной. В противном случае вы не могли бы получить к нему доступ из xaml.

Вы можете удалить

var persons = new List<Person>();

И замените его свойством в вашем классе MainWindow.

public ObservableCollection<Person> Persons {get; set;}

Ваш класс должен выглядеть

public ObservableCollection<Person> Persons {get; set;}

public MainWindow()
    {
        InitializeComponent();

        var lines = File.ReadAllLines(filepath);
        Persons = new ObservableCollection<Person>();

И в вашем DataGrid смените привязку на ItemsSource="{Binding Persons}"

15.03.2017
  • Спасибо @Mighty Badaboom, я попробую ваш ответ. Но не могли бы вы объяснить, что означает FirstOrDefault? Кроме того, как можно привязать это к представлению списка, которое у меня есть? Спасибо еще раз 15.03.2017
  • FirstOrDefault даст вам первое совпадение. Если ни один элемент не соответствует, вы получите нуль. Взгляните на code.msdn.microsoft.com/101-LINQ-Samples- 3fb9811b, чтобы ознакомиться с LINQ. Это очень полезно. При привязке к вашему xaml я бы использовал ObservableCollection‹Person› вместо List‹T›. Как вы хотите отображать свои данные? Думаю, DataGrid будет хорошим выбором. Привяжите своего человека к ItemsSource DataGrid. Если у вас есть проблемы, опубликуйте свой код, и я могу вам помочь. 15.03.2017
  • Большое спасибо! В настоящее время я сохраняю файл CSV в список и отображаю его в виде списка. Но я не уверен, что делаю это правильно, потому что у меня есть два списка, и каждый столбец находится в другом списке. Это правильный подход? 15.03.2017
  • Это не лучший подход, потому что вы храните зависимые данные в двух разных элементах управления. Дайте мне минуту, и я изменю свой пост, чтобы дать вам пример. 15.03.2017
  • Отредактировал мой пост для краткого примера. 15.03.2017
  • Большое спасибо за ваш короткий пример и за ваше объяснение. Я попробую сейчас. Еще один вопрос: нужно ли мне привязывать класс Person в моем MainWindow() в качестве источника элементов для сетки данных? Или это не нужно, так как это уже сделано в XAML? Спасибо еще раз! 15.03.2017
  • Не нужно, когда вы сделали это в XAML (что является лучшим и самым чистым способом). Еще один совет: когда вы это сделаете, вам следует взглянуть на шаблон MVVM. Это шаблон для разработки приложений WPF. 15.03.2017
  • Потрясающий! Я попробую это и посмотрю на MVVM. Большое спасибо за вашу огромную помощь и за то, что были терпеливы со мной!! :) 15.03.2017
  • Добро пожаловать. Если это сработает, я буду благодарен вам за то, что вы приняли мой ответ и/или проголосовали за него. Удачи и наслаждайтесь WPF;) 15.03.2017
  • Кажется, мне еще понадобится ваша помощь :) Я только что попробовал. и он работал без ошибок, но сетка данных пуста и не показывает никаких данных. Я опубликую свой код, чтобы показать вам, все ли в порядке 15.03.2017
  • Отредактировал мой ответ. 15.03.2017
  • Большое спасибо. Для обновления вашего ответа. Я никогда раньше не использовал наблюдаемую коллекцию, поэтому я немного смущен тем, почему нам нужно было создать класс с именем Person, затем наблюдаемую коллекцию Persons, а затем снова использовать Persons в этой строке: var person = Persons.FirstOrDefault(x => x .Имя == имя); ? 15.03.2017
  • ObservableCollection связан с тем, что он реализует INotifyProperyChange для обновления вашего представления при возникновении изменений. Класс Person предназначен для одного человека. У вас есть x человек, поэтому вам нужна коллекция для их хранения. В кавычках вы проверяете, существует ли человек с таким именем. Если да, вы можете увеличить ее счет. Если нет, создайте нового человека и поместите его в список. 15.03.2017
  • Спасибо за объяснение. Я внес изменения, и все еще ничего не отображается в сетке данных. Кажется, что код работает нормально, потому что я запускал код в режиме отладки и следил за каждой строкой, чтобы увидеть, действительно ли код вычисляет сумму, и это так. Но он не отображается в сетке данных. Может быть, сетка данных неправильно привязана к сгенерированным данным? 16.03.2017
  • Неважно, я заставил его работать. Я подумал, что попытаюсь связать сетку данных с результатами, которые я получаю от Persons в моем MainWindow(). Поэтому я добавил эту строку в свой MainwWindow(): datagrid.ItemsSource = Persons; и это заставило его работать :) Большое спасибо за всю вашу помощь и ваши четкие объяснения. Вы мне очень помогли, я многому у вас научился :) 16.03.2017

  • 2

    Я бы использовал словарь:

    public MainWindow()
    {
        InitializeComponent();      
        using (var fs = File.OpenRead(filepath))
        using (var reader = new StreamReader(fs))
        {
            var dict = new Dictionary<string, int>();
            while (!reader.EndOfStream)
            {
                var line = reader.ReadLine();
                var values = line.Split(',');
    
                // Discard header line
                if (("Name" == values[0]) && ("Score" == values[1]))
                    continue;
    
                if (dict.ContainsKey(values[0]))
                    dict[values[0]] += Convert.ToInt32(values[1]);
                else
                    dict[values[0]] = Convert.ToInt32(values[1]);
            }
    
            // Now you can create some lists to display
            var list0 = new List<string>();
            var list1 = new List<string>();
            foreach (KeyValuePair<string, string> entry in dict)
            {
                list0.Add(entry.Key);
                list1.Add(entry.Value.ToString());
            }
    
            List0.ItemsSource = list0;
            List1.ItemsSource = list1; 
         }
    }
    
    15.03.2017
  • Привет, dumetrulo, спасибо за ваш комментарий. Я попробую это, но в чем преимущества использования словаря? Я никогда раньше им не пользовался. Спасибо! 15.03.2017
  • Я предполагаю, что в строке foreach вы имели в виду: foreach (KeyValuePair‹string, int› запись в dict), а не ‹string, string› верно? 15.03.2017
  • Я бы использовал класс вместо KeyValuePairs с магическими строками. Взгляните на мой ответ для примера. 15.03.2017
  • Я тоже попробовал ваш ответ, и он тоже сработал со мной. Я никогда не знал, что могу использовать словари в C#, поэтому буду читать об этом. Большое спасибо за твою помощь :) 16.03.2017
  • Новые материалы

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

    Работа с цепями Маркова, часть 4 (Машинное обучение)
    Нелинейные цепи Маркова с агрегатором и их приложения (arXiv) Автор : Бар Лайт Аннотация: Изучаются свойства подкласса случайных процессов, называемых дискретными нелинейными цепями Маркова..

    Crazy Laravel Livewire упростил мне создание электронной коммерции (панель администратора и API) [Часть 3]
    Как вы сегодня, ребята? В этой части мы создадим CRUD для данных о продукте. Думаю, в этой части я не буду слишком много делиться теорией, но чаще буду делиться своим кодом. Потому что..

    Использование машинного обучения и Python для классификации 1000 сезонов новичков MLB Hitter
    Чему может научиться машина, глядя на сезоны новичков 1000 игроков MLB? Это то, что исследует это приложение. В этом процессе мы будем использовать неконтролируемое обучение, чтобы..

    Учебные заметки: создание моего первого пакета Node.js
    Это мои обучающие заметки, когда я научился создавать свой самый первый пакет Node.js, распространяемый через npm. Оглавление Глоссарий I. Новый пакет 1.1 советы по инициализации..

    Забудьте о Matplotlib: улучшите визуализацию данных с помощью умопомрачительных функций Seaborn!
    Примечание. Эта запись в блоге предполагает базовое знакомство с Python и концепциями анализа данных. Привет, энтузиасты данных! Добро пожаловать в мой блог, где я расскажу о невероятных..

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


    Для любых предложений по сайту: [email protected]