如何在 C# .NET 中融化 DataTable(从宽到长格式)?

How to melt a DataTable in C# .NET (wide to long format)?

如何像 Python Pandas.melt 那样在 C#(宽到长格式)中融化 DataTablehttps://pandas.pydata.org/docs/reference/api/pandas.melt.html

有没有已经实现的方法?如果不是,融化 DataTable 的代码将如何

例如:

我有一个宽格式的 DataTable,每个 id 一行,列数与变量一样多。我想将此 DataTable 转换为长格式,其行数与 id 与每个变量列的组合一样多。您可以在顶部图片中看到此示例。

拜托,如果不够清楚请访问Pandas文档,那里更清楚。 (https://pandas.pydata.org/docs/reference/api/pandas.melt.html)

注意:我想要一个独立于 DataTable 的解决方案,也就是说,该解决方案能够将参数作为 id_varsvalue_vars 等...如 Pandas.melt确实

感谢任何帮助。

我不知道 Melt 方法,但根据 docs 它似乎是一个逆轴方法:

public static DataTable MeltTable(DataTable inputTable, string outputColumn, params string[] unpivotColumns)
{
    DataTable resultTable = new DataTable();
    DataColumn col = new DataColumn(outputColumn, inputTable.Columns[outputColumn].DataType);
    resultTable.Columns.Add(col);
    resultTable.Columns.Add("Variable");
    resultTable.Columns.Add("Value");
    foreach(string unpivotColumn in unpivotColumns)
    {
        foreach (DataRow row in inputTable.Rows)
        {
            resultTable.Rows.Add(row[outputColumn], unpivotColumn, row[unpivotColumn]);
        }
    }
    
    return resultTable;
}

你是这样使用的:

DataTable table = new DataTable();
table.Columns.Add("Name");
table.Columns.Add("Course");
table.Columns.Add("Age", typeof(int));
table.Rows.Add("Tim", "Masters", 47);
table.Rows.Add("Bob", "Graduate", 19);
table.Rows.Add("Sheila", "Graduate", 20);
DataTable resultTable = MeltTable(table, "Name", "Course", "Age");

结果:

Name    Variable     Value
Tim     Course       Masters
Bob     Course       Graduate 
Sheila  Course       Graduate 
Tim     Age          47 
Bob     Age          19 
Sheila  Age          20 

@TimSchmelter 给了我答案,但我做了一些修改以成为更通用的解决方案。这是代码:

    public static List<string> GetDifferenceColumns(DataTable dt, List<string> diffCols)
    {
        string[] columns = GetColumnsList(dt).ToArray();
        IEnumerable<string> differenceColumns = from column in columns.Except(diffCols.ToArray()) select column;
        return differenceColumns.ToList();


    }

    public static DataTable Melt(DataTable dt, List<string> idCols = null, List<string> varCols = null)
    {
        string errorPrefixString = "Error in DataProcessing Melt Method:\n";
        bool varsColsIsNull = (varCols == null || varCols.Count == 0);
        bool idColsIsNull = (idCols == null || idCols.Count == 0);
        string varsName = "Variable";
        string valueName = "Value";
        if (dt.Rows.Count == 0)
        {
            throw new Exception(errorPrefixString + "DataTable is empty");
        }
        if (varsColsIsNull && varsColsIsNull)
        {
            throw new Exception(errorPrefixString+"You should past at least varCols or idCols");
        }
        if (varsColsIsNull)
        {
            varCols = GetDifferenceColumns(dt, idCols);
        }
        if (idColsIsNull)
        {
            idCols = GetDifferenceColumns(dt, varCols);
        }

        DataTable resultTable = new DataTable();
        // Creating final columns of resultTable
        foreach (string id in idCols)
        {
            resultTable.Columns.Add(id);
        }
        resultTable.Columns.Add(varsName);
        resultTable.Columns.Add(valueName);
        
        // Populating resultTable with the new rows
        // generated by unpivoting varCols
        foreach (string varCol in varCols)
        {
            foreach (DataRow row in dt.Rows)
            {
                DataRow resultRow = resultTable.NewRow();
                foreach(string id in idCols)
                {
                    resultRow[id] = row[id]; // create id cols
                }
                resultRow[varsName] = varCol;
                resultRow[valueName] = row[varCol];
                resultTable.Rows.Add(resultRow);

            }
        }
        return resultTable;
    }

使用方法:

    DataTable dt = new DataTable();
    dt.Columns.Add("Name");
    dt.Columns.Add("Course");
    dt.Columns.Add("Age");
    dt.Rows.Add("Tim", "Masters", 47);
    dt.Rows.Add("Bob", "Graduate", 19);
    dt.Rows.Add("Sheila", "Graduate", 20);
    List<string> varCols = new List<string> { "Course", "Age" };
    DataTable finalDataTable = Melt(dt, varCols: varCols);