Как разбить строку с данными на несколько строк на основе разделения символов в .net - PullRequest
0 голосов
/ 08 июня 2019

У меня есть таблица данных, как показано ниже

Dosage  Drug            Patient
-----------------------------------
  25    Indocin         David
  50    Enebrel,Crozine Sam
  10    Hydralazine     Christoff
  21    Combivent       Janet
 100    Dilantin        Melanie

, которая должна быть преобразована в, как показано ниже на основе разделения запятых

Dosage  Drug            Patient
------------------------------
  25    Indocin         David
  50    Enebrel         Sam
  50    Crozine         Sam
  10    Hydralazine     Christoff
  21    Combivent       Janet
 100    Dilantin        Melanie

Я сделал следующий код, который не даетожидаемый результат.Может кто-нибудь предложить ответ?

private static void ProcessDatatable(DataTable dt)
{
    DataTable dtnew = new DataTable();

    IEnumerable<string[]> allRowValues = dt.AsEnumerable()
                                           .Select(r => r.Field<string>(1).Split(','));

    dtnew = allRowValues.ToDataTable();
}

Метод расширения:

public static DataTable ToDataTable<T>(this IEnumerable<T> collection, string tableName)
{
    DataTable tbl = ToDataTable(collection);
    tbl.TableName = tableName;

    return tbl;
}

public static DataTable ToDataTable<T>(this IEnumerable<T> collection)
{
    DataTable dt = new DataTable();

    Type t = typeof(T);

    PropertyInfo[] pia = t.GetProperties();

    // Create the columns in the DataTable
    foreach (PropertyInfo pi in pia)
    {
        dt.Columns.Add(pi.Name, pi.PropertyType);
    }

    // Populate the table
    foreach (T item in collection)
    {
        DataRow dr = dt.NewRow();

        dr.BeginEdit();

        foreach (PropertyInfo pi in pia)
        {
             dr[pi.Name] = pi.GetValue(item, null);
        }

        dr.EndEdit();

        dt.Rows.Add(dr);
    }

    return dt;
}

Ответы [ 2 ]

2 голосов
/ 09 июня 2019

То, что вы думаете, что вы хотите, это:

IEnumerable<object[]> allRowValues = dataTable.AsEnumerable()
    .SelectMany(dataRow =>
        dataRow.Field<string>(1).Split(',').Select(drug => new[] { dataRow[0], drug, dataRow[2] }));

Но то, что вы действительно хотите, это:

IEnumerable<Record> allRowValues = dataTable.AsEnumerable()
    .Select(dataRow => new Record(dataRow))
    .SelectMany(record => record.SplitDrugs());

// ...

public class Record
{
    public int Dosage { get; }
    public string Drug { get; }
    public string Patient { get; }

    public Record(int dosage, string drug, string patient)
    {
        Dosage = dosage;
        Drug = drug;
        Patient = patient;
    }

    public Record(DataRow dataRow)
        : this((int)dataRow["Dosage"], (string)dataRow["Drug"], (string)dataRow["Patient"])
    {
    }

    public IEnumerable<Record> SplitDrugs()
    {
        return Drug.Split(',').Select(drug => new Record(Dosage, drug, Patient));
    }
}

Краткое объяснение: с причудливым LINQ вы пытаетесь решить простослишком много мировых проблем извлекают информацию из таблицы данных, обрабатывают строки по очереди, применяют бизнес-логику и объединяют результат с новой таблицей данных.Это хороший способ написать подверженный ошибкам, нечитаемый, непроверяемый, нестабильный и не подлежащий обработке код.

Неполный список людей, которые в конечном итоге будут благодарны вам за выбор второго варианта:

  • твое будущее
  • твои товарищи по команде
  • твой рецензент кода
  • юнит-тестировщик
  • конечный пользователь
  • ваш учитель (если задание)
  • ТАК сообщество

Пока я в нем, я сэкономлю вам время на отладку преобразования allRowValues (которое в вашем случае имеетвведите IEnumerable<string[]>) назад к DataTable.Если вы думаете, что он будет содержать 3 столбца, то вы ошибаетесь.Вместо этого он будет содержать столбцы, такие как Length, LongLength, Rank, ... Посмотрите на properties Массив класса , чтобы выяснить, почему.

Edit

OP уточнил исходное намерение в комментарии под другим ответом.

..., но я только что опубликовал прототип данных, в действительности там есть 180 столбцов. ДО мне нужно добавитьвсе 180 столбцов вручную в newRow.ItemArray, когда есть разделение значений, разделенных запятыми ??? Любой более простой способ?

Да, есть более простой способ.Привлекая обобщения, вы можете расширить использование за пределы этого ограниченного варианта использования:

// extension method
public static DataTable ExpandColumn<T>(this DataTable dataTable, string columnName,
    Func<T, IEnumerable<T>> expandField)
{
    var clonedDataTable = dataTable.Clone();
    var columnIndex = dataTable.Columns.IndexOf(columnName);
    var column = dataTable.Columns[columnIndex];
    foreach (var dataRow in dataTable.AsEnumerable())
    {
        var valueToExpand = dataRow.Field<T>(column);
        var expandedValues = expandField(valueToExpand);
        var originalValues = dataRow.ItemArray;
        foreach (var value in expandedValues)
        {
            originalValues[columnIndex] = value;
            clonedDataTable.Rows.Add(originalValues);
        }
    }
    return clonedDataTable;
}

// usage
var dataTableNew = dataTable.ExpandColumn<string>("Drug", drug => drug.Split(','));

Приведенный выше метод расширения клонирует DataTable экземпляр, копируя исходные строки и расширяя значения в указанном столбце, применяя функцию expandField для каждого значения.

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

1 голос
/ 09 июня 2019

Мне очень плохо с C #, поэтому мне пришлось делать это по старинке, но это работает.

public partial class Form1 : Form
{
    private DataTable dt;
    private DataTable dtExpanded;

    public Form1()
    {
        InitializeComponent();
        LoadTable();
        LoadExpandedTable();
    }
    //Dosage Drug            Patient
   private void LoadTable()
    {
        dt = new DataTable();
        using (SqlConnection cn = new SqlConnection("Your connection string"))
        {
            using (SqlCommand cmd = new SqlCommand("Select * From DrugDoses", cn))
            {
                cn.Open();
                dt.Load(cmd.ExecuteReader());
            }
        }
        dataGridView1.DataSource = dt;
    }
    private void LoadExpandedTable()
    {
        dtExpanded = new DataTable();
        dtExpanded.Columns.Add("Dose");
        dtExpanded.Columns.Add("Drug");
        dtExpanded.Columns.Add("Patient");
        foreach (DataRow r in dt.Rows)
        {
            string s = (string)r["Drug"];
            if(s.Contains(","))
            {
                string[] splitName = s.Split(',');
                foreach (string drug in splitName)
                {
                    DataRow newRow = dtExpanded.NewRow();
                    newRow.ItemArray = new Object[] { r["Dosage"], drug , r["Patient"]};
                    dtExpanded.Rows.Add(newRow);
                }
            }
            else
            {
                dtExpanded.Rows.Add(r.ItemArray);
            }

        }
        dataGridView2.DataSource = dtExpanded;
    }
}
...