Как импортировать данные из текстовых файлов .csv с разными заголовками столбцов в память

Я пытаюсь читать данные из файла CSV по одной строке за раз. Первая строка, заголовки столбцов, определяет тип данных в каждой строке. Я уже знаю, что все данные принадлежат классу, который есть в моем проекте под названием UserModel, но я пытаюсь сделать это без жесткого кодирования данных в поля UserModel. Я могу прочитать первые пару строк и правильно создать первый экземпляр пользовательской модели. Но все разваливается, когда я пытаюсь прочитать третью строчку. Я использую словарь и пытаюсь использовать экземпляр созданного словаря, когда читаю первые пару строк. Смысл использовать порядок ключей в экземпляре Dictionary и просто обновлять значения следующим набором данных, но я не могу понять, почему набор данных просто не совпадает с нужными ключами.

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

public class MyData 
{
    BindingList<UserModel> users = new BindingList<UserModel>();
    UserModel currentUser = new UserModel();

    public BindingList<UserModel> GetUsers()
    {

        string[] lines = File.ReadAllLines("StandardDataSet.csv");
        // Add error handing to make sure all lines have four enteris 
        foreach (string line in lines.Skip(1))
        {
            //I am not sure how to handle the first line that is a header
            string [] values = line.Split(',').Select(x => x.Trim()).ToArray();
            currentUser.FirstName = values[0];
            currentUser.LastName = values[1];
            int.TryParse(values[2], out int age);
            currentUser.Age = age;
            bool.TryParse(values[3], out bool alive);
            currentUser.IsAlive = alive;
            users.Add(currentUser);
        }
        return users;
    }
private static T DictionaryToObject<T>(IDictionary<string, object> dict) where T : new()
    {
        T t = new T();
        PropertyInfo[] properties = t.GetType().GetProperties();

        foreach (PropertyInfo property in properties)
        {
            if (!dict.Any(x => x.Key.Equals(property.Name, StringComparison.InvariantCultureIgnoreCase)))
                continue;
            KeyValuePair<string, object> item = dict.First(x => x.Key.Equals(property.Name, StringComparison.InvariantCultureIgnoreCase));
            Type tPropertyType = t.GetType().GetProperty(property.Name).PropertyType;
            Type newT = Nullable.GetUnderlyingType(tPropertyType) ?? tPropertyType;
            //if (item.Value is '0') Convert.ToBoolean(Convert.ToInt32(item.Value));
            object newA = Convert.ChangeType(item.Value, newT);
            t.GetType().GetProperty(property.Name).SetValue(t, newA, null);
        }
        return t;
    }
public BindingList<UserModel> GetUsersAdvanced()
    {
        users = new BindingList<UserModel>();
        var dict= new Dictionary<string,object>();
        string[] lines = File.ReadAllLines("AdvancedDataSet.csv");
        var header = lines.First().Split(',');
        var data = lines.Skip(1).First().Split(',');


        for (int i = 0; i < header.Length; i++)
            {
                if (data[i] == "0" || data[i] == "1")
                    {
                        Boolean IsAlive = Extensions.ToBoolean(data[i]);
                        dict.Add(header[i], IsAlive);
                    }
                else
                //if (data[i]!= "0" || data[i]! = "1")
                dict.Add(header[i], data[i]);
        }   
        currentUser = DictionaryToObject<UserModel>(dict);
        var dictCopy = new Dictionary<string, object>(dict);
        var dictConcurrent = new ConcurrentDictionary<string, object>(dict);

    foreach (var line in lines.Skip(1))
    {
    if (line != null)  data = line.Split(',');

                foreach (var key in dict.Keys)
                {
                int i = 0;
                if (data[i] == "0" || data[i] == "1")
                    {
                        Boolean IsAlive = Extensions.ToBoolean(data[i]);
                        dictCopy[key] = IsAlive;
                        i++;
                        continue;
                    }
                    else
                    dictCopy[key] = data[i];
                    i++;  
                 }
                 currentUser = DictionaryToObject<UserModel>(dictCopy);
                 users.Add(currentUser);
                 currentUser = new UserModel();

    }
 return users;
}

Существует множество инструментов и библиотек, которые сделают все это за вас... и сделают это довольно хорошо.

Ňɏssa Pøngjǣrdenlarp 31.05.2019 01:27
Хватит писать собственный парсер CSV; формат сложнее, чем вы думаете. Существует множество рабочие парсеры CSV, которые вы можете добавить в свое приложение.
Dour High Arch 31.05.2019 01:46

Я добавлю к припеву, использую библиотеку

TheGeneral 31.05.2019 01:58
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
3
56
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Как говорится в комментариях людей, я также рекомендую использовать существующие библиотеки. Обычно они также поддерживают такие сопоставление данных с объектом и конверсия данных, которые вы делаете в своем коде. Итак, сначала попробуйте один или два.

Как насчет:

Кстати по порядку элементов в Dictionary можно прочитать причину здесь

For purposes of enumeration, each item in the dictionary is treated as a KeyValuePair structure representing a value and its key. The order in which the items are returned is undefined.

Итак, как насчет сохранения заголовков столбцов в списке? Таким образом, вы можете сохранить порядок. Код будет примерно таким, как показано ниже.

Но, пожалуйста, возьмите это как пример для заказанных товаров. Опять же, сначала попробуйте некоторые библиотеки, тогда вы увидите более интересные функции и получите более аккуратный код с ними.

public BindingList<UserModel> GetUsersAdvanced()
{
    users = new BindingList<UserModel>();
    string[] lines = File.ReadAllLines("AdvancedDataSet.csv");
    var cols = lines.First().Split(',').ToList();

    // validate column name duplication here!

    foreach (var line in lines.Skip(1))
    {
        if (line != null)  data = line.Split(',');

        for (var i = 0; i < cols.Count(); i++)
        {
            var key = cols[i];
            var dict = new Dictionary<string, object>();

            if (data[i] == "0" || data[i] == "1")
            {
                Boolean IsAlive = Extensions.ToBoolean(data[i]);
                dict.Add(key, IsAlive);
            }
            else
                dict.Add(key, data[i]);

            var currentUser = DictionaryToObject<UserModel>(dict);
            users.Add(currentUser);
        }

        return users;
    }
}

Спасибо большое. Я делал это, чтобы учиться, и надеялся, что кто-то откликнется.

Shahin 31.05.2019 04:34

Другие вопросы по теме