多列数据转换

2024-03-05

我正在从数据源接收数据,在将信息发送到 UI 进行显示之前,我需要先进行数据透视。I am new to concept of pivoting & I am not sure how to go about it.

问题有两个部分:

  1. 形成标题
  2. 旋转数据以匹配标题

要记住的事情:

  1. 我有一些我不想旋转的列。我称他们为static columns.

  2. 我需要旋转某些列以形成多级标题信息。我称他们为dynamic columns

  3. 某些包含实际值的列需要进行透视。我打电话给他们value columns.

  4. NO limit就数量而言dynamic, static and value columns一个可以拥有。

  5. 假设,当数据到来时,我们将首先获得静态列的数据,然后是动态列的数据,然后是值列的数据。

    请参阅附图了解更多信息。

虚拟数据:

class Program
    {
        static void Main(string[] args)
        {
            var _staticColumnCount = 2; //Columns that should not be pivoted        
            var _dynamicColumnCount = 2; // Columns which needs to be pivoted to form header            
            var _valueColumnCount = 1; //Columns that represent Actual value        
            var valueColumnIndex = 4; //Assuming index starts with 0;

            List<List<string>> headerInfo = new List<List<string>>();
            headerInfo.Add(new List<string> {"Product Three", "Item Ten"});
            headerInfo.Add(new List<string> {"Product Two", "Item Five"});
            headerInfo.Add(new List<string> {"Product Two", "Item Seven"});
            headerInfo.Add(new List<string> {"Product Two", "Item Nine"});
            headerInfo.Add(new List<string> {"Product One", "Item One"});
            headerInfo.Add(new List<string> {"Product One", "Item Two"});
            headerInfo.Add(new List<string> {"Product One", "Item Four"});
            headerInfo.Add(new List<string> {"Product One", "Item Six"});
            headerInfo.Add(new List<string> {"Product One", "Item Eight"});
            headerInfo.Add(new List<string> {"Product One", "Item Eleven"});


            List<List<string>> data = new List<List<string>>();
            data.Add(new List<string> {"Global", "Europe", "Product One", "Item One", "579984.59"});
            data.Add(new List<string> {"Global", "North America", "Product One", "Item Two", "314586.73"});
            data.Add(new List<string> {"Global", "Asia", "Product One", "Item One", "62735.13"});
            data.Add(new List<string> {"Global", "Asia", "Product Two", "Item Five", "12619234.69"});
            data.Add(new List<string> {"Global", "North America", "Product Two", "Item Five", "8953713.39"});
            data.Add(new List<string> {"Global", "Europe", "Product One", "Item Two", "124267.4"});
            data.Add(new List<string> {"Global", "Asia", "Product One", "Item Four", "482338.49"});
            data.Add(new List<string> {"Global", "North America", "Product One", "Item Four", "809185.13"});
            data.Add(new List<string> {"Global", "Europe", "Product One", "Item Four", "233101"});
            data.Add(new List<string> {"Global", "Asia", "Product One", "Item Two", "120561.65"});
            data.Add(new List<string> {"Global", "North America", "Product One", "Item Six", "1517359.37"});
            data.Add(new List<string> {"Global", "Europe", "Product One", "Item Six", "382590.45"});
            data.Add(new List<string> {"Global", "North America", "Product One", "Item Eight", "661835.64"});
            data.Add(new List<string> {"Global", "Europe", "Product Three", "Item Three", "0"});
            data.Add(new List<string> {"Global", "Europe", "Product One", "Item Eight", "0"});
            data.Add(new List<string> {"Global", "Europe", "Product Two", "Item Five", "3478145.38"});
            data.Add(new List<string> {"Global", "Asia", "Product One", "Item Six", "0"});
            data.Add(new List<string> {"Global", "North America", "Product Two", "Item Seven", "4247059.97"});
            data.Add(new List<string> {"Global", "Asia", "Product Two", "Item Seven", "2163718.01"});
            data.Add(new List<string> {"Global", "Europe", "Product Two", "Item Seven", "2158782.48"});
            data.Add(new List<string> {"Global", "North America", "Product Two", "Item Nine", "72634.46"});
            data.Add(new List<string> {"Global", "Europe", "Product Two", "Item Nine", "127500"});
            data.Add(new List<string> {"Global", "North America", "Product One", "Item One", "110964.44"});
            data.Add(new List<string> {"Global", "Asia", "Product Three", "Item Ten", "2064.99"});
            data.Add(new List<string> {"Global", "Europe", "Product One", "Item Eleven", "0"});
            data.Add(new List<string> {"Global", "Asia", "Product Two", "Item Nine", "1250"});


        }
    }

你叫什么static columns通常被称为行组, dynamic columns - 列组 and value columns - 价值总量或简单values.

为了实现这一目标,我建议使用以下简单的数据结构:

public class PivotData
{
    public IReadOnlyList<PivotValues> Columns { get; set; }
    public IReadOnlyList<PivotDataRow> Rows { get; set; }
}

public class PivotDataRow
{
    public PivotValues Data { get; set; }
    public IReadOnlyList<PivotValues> Values { get; set; }
}

The Columns成员PivotData将代表你所说的header,而Row成员 - 列表PivotDataRow对象与Data成员包含行组价值观和Values - the values对于相应的Columns index (PivotDataRow.Values总会有相同的Count as PivotData.Columns.Count).

上述数据结构可序列化/反序列化为 JSON(使用 Newtonsoft.Json 测试),可用于以所需格式填充 UI。

用于表示行组值、列组值和聚合值的核心数据结构是这样的:

public class PivotValues : IReadOnlyList<string>, IEquatable<PivotValues>, IComparable<PivotValues>
{
    readonly IReadOnlyList<string> source;
    readonly int offset, count;
    public PivotValues(IReadOnlyList<string> source) : this(source, 0, source.Count) { }
    public PivotValues(IReadOnlyList<string> source, int offset, int count)
    {
        this.source = source;
        this.offset = offset;
        this.count = count;
    }
    public string this[int index] => source[offset + index];
    public int Count => count;
    public IEnumerator<string> GetEnumerator()
    {
        for (int i = 0; i < count; i++)
            yield return this[i];
    }
    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
    public override int GetHashCode()
    {
        unchecked
        {
            var comparer = EqualityComparer<string>.Default;
            int hash = 17;
            for (int i = 0; i < count; i++)
                hash = hash * 31 + comparer.GetHashCode(this[i]);
            return hash;
        }
    }
    public override bool Equals(object obj) => Equals(obj as PivotValues);
    public bool Equals(PivotValues other)
    {
        if (this == other) return true;
        if (other == null) return false;
        var comparer = EqualityComparer<string>.Default;
        for (int i = 0; i < count; i++)
            if (!comparer.Equals(this[i], other[i])) return false;
        return true;
    }
    public int CompareTo(PivotValues other)
    {
        if (this == other) return 0;
        if (other == null) return 1;
        var comparer = Comparer<string>.Default;
        for (int i = 0; i < count; i++)
        {
            var compare = comparer.Compare(this[i], other[i]);
            if (compare != 0) return compare;
        }
        return 0;
    }
    public override string ToString() => string.Join(", ", this); // For debugging
}

基本上它代表了一个范围(切片)string具有相等和顺序比较语义的列表。前者允许在数据透视转换期间使用基于哈希的高效 LINQ 运算符,而后者允许可选排序。此外,此数据结构允许高效转换,无需分配新列表,同时在从 JSON 反序列化时保存实际列表。

(平等比较是通过实施提供的IEquatable<PivotValues>界面 -GetHashCode and Equals方法。通过这样做,它可以治疗两个PivotValues类实例根据指定范围内的值相等List<string>输入的元素List<List<string>>。类似地,排序是通过实现IComparable<PivotValues>界面 -CompareTo方法))

转换本身非常简单:

public static PivotData ToPivot(this List<List<string>> data, int rowDataCount, int columnDataCount, int valueDataCount)
{
    int rowDataStart = 0;
    int columnDataStart = rowDataStart + rowDataCount;
    int valueDataStart = columnDataStart + columnDataCount;

    var columns = data
        .Select(r => new PivotValues(r, columnDataStart, columnDataCount))
        .Distinct()
        .OrderBy(c => c) // Optional
        .ToList();

    var emptyValues = new PivotValues(new string[valueDataCount]); // For missing (row, column) intersection

    var rows = data
        .GroupBy(r => new PivotValues(r, rowDataStart, rowDataCount))
        .Select(rg => new PivotDataRow
        {
            Data = rg.Key,
            Values = columns.GroupJoin(rg,
                c => c,
                r => new PivotValues(r, columnDataStart, columnDataCount),
                (c, vg) => vg.Any() ? new PivotValues(vg.First(), valueDataStart, valueDataCount) : emptyValues
            ).ToList()
        })
        .OrderBy(r => r.Data) // Optional
        .ToList();

    return new PivotData { Columns = columns, Rows = rows };
}

首先,使用简单的 LINQ 确定列(标题)Distinct操作员。然后通过按行列对源集进行分组来确定行。每行分组内的值是通过外部连接确定的Columns与分组内容。

由于我们的数据结构实现,LINQ 转换非常高效(对于空间和时间)。列和行的顺序是可选的,如果不需要,只需将其删除即可。

使用虚拟数据进行示例测试:

var pivotData = data.ToPivot(2, 2, 1);
var json = JsonConvert.SerializeObject(pivotData);
var pivotData2 = JsonConvert.DeserializeObject<PivotData>(json);
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

多列数据转换 的相关文章

随机推荐

  • 如何检测我是否在 next.js 中的客户端服务器上?

    我正在使用带有 Next js 的客户快递服务器 它在容器内运行 我正在做一个http请求isomorphic fetch获取我的渲染数据 我想做localhost当在服务器上运行时mysite com在客户端运行时 不确定实现此目的的最佳
  • 如何将 javascript 函数存储在队列中以便最终执行它们[重复]

    这个问题在这里已经有答案了 我在 javascript 中创建了一个 Queue 类 我想将函数作为数据存储在队列中 这样我就可以建立请求 函数调用 并在需要时响应它们 实际执行函数 有没有什么方法可以将函数存储为数据 有点类似于 setT
  • xmlserializer 未通过导入正确反序列化架构

    我一直在尝试使用从 xsd exe 中的架构生成的类来反序列化 C 中的 xml 文件 不幸的是 只有部分文件被正确反序列化 其余部分由于我无法解决的原因而返回为空 我的流程如下 从生成 C 代码的 myschema xsd 文件开始
  • PyEnv BUILD 在 MacOS 上安装 Python 失败

    尝试安装时Python 3 6 6 for Airflow using PyEnv on MacOS 我遇到构建失败与以下堆栈跟踪 File private var folders 6y kf699bqj2sgcgjshb20fr5zh00
  • 关于 AT&T x86 语法设计的问题

    谁能向我解释为什么 AT T 语法中的每个常量前面都有一个 为什么所有寄存器都有 这是否只是又一次试图让我做很多蹩脚的打字 另外 我是唯一一个发现 16 esp 相比之下确实违反直觉 esp 16 我知道它编译成同样的东西 但为什么有人想在
  • Docker 数据卷容器 - 我可以在 swarm 之间共享吗

    我知道如何使用 volumes from 创建数据卷容器并将其安装到多个其他容器 但我确实有一些关于它的用法和限制的问题 情况 我希望使用数据卷容器来为我的 Web 应用程序存储用户上传的图像 此数据卷容器将由运行 Web 前端的许多其他容
  • jQuery 检测点击禁用的提交按钮

    Fiddle http jsfiddle net ugzux http jsfiddle net ugzux 如您所见 我有一个带有禁用 通过 javascript 提交按钮的表单 无论如何 我希望能够将单击事件绑定到它 这样我就可以在允许
  • ARKitestimatedVerticalPlane命中测试获取平面旋转

    我正在使用 ARKit 在运行时检测墙壁 当触摸屏幕的某个点时 我使用 estimatedVerticalPlane 类型的命中测试 我正在尝试将 Y 旋转应用于与检测到的平面方向相对应的节点 我想计算旋转 private func com
  • VBA 将工作表保存到受密码保护的 PDF

    以下命令将活动表另存为 PDF ActiveSheet ExportAsFixedFormat Type xlTypePDF Filename C blahblah2 pdf Quality xlQualityStandard Ignore
  • 使用 Dancer 和 Postgres 的简单登录/授权系统

    作为 Perl 的新手 我正在努力寻找一种简单的方法来做到这一点 我在数据库中创建了一个非常简单的表 CREATE TABLE users id SERIAL NOT NULL PRIMARY KEY username TEXT NOT N
  • 如何在 Yii2 html::dropdownlist 中保留所选值?

    我认为有以下代码 and submit button 我的代码运行良好 但有一个大问题 我选择一个区域并单击搜索按钮 结果正确 当我单击下一页时 每页显示 10 个结果 它给了我
  • 如何在 WinDbg 中删除断点 ntdll!DbgBreakPoint+0x1

    我正在调试一个在将 WinDbg 设置为事后调试器时崩溃的程序 我在地址 77f7f571 设置了断点 当它被触发时 我常常得到以下信息 ERROR Symbol file could not be found Defaulted to e
  • 导入库 Oshi

    我想开发一个显示计算机信息的程序 我找到了一个名为 Oshi https github com oshi oshi 当我导入该库并运行我的代码时 出现异常 Exception in thread main java lang NoClass
  • 无法从 CursorWindow 读取第 0 行第 9 列

    我收到错误无法从 CursorWindow 读取第 0 行 第 9 列 在访问游标中的数据之前 请确保游标已正确初始化 另外两个人能够毫无错误地运行代码 但在我的机器上它会抛出错误 我很困惑 下面是处理 SQLite 的代码 提前致谢 抱歉
  • 如何使用 Arcore 截屏?

    我正在尝试截取增强现实屏幕的屏幕截图并将其作为位图传递给另一个活动 这是我用来截取屏幕截图的代码 截图功能 public static void tmpScreenshot Bitmap bmp Context context try Wr
  • 在聚集索引上使用顺序 GUID 键插入的速度并没有明显加快

    在 SQL Server 2008 中 我尝试重现顺序与非顺序 GUID 键上的聚集索引的实验结果 如下所示http sqlblog com blogs denis gobo archive 2009 02 05 11743 aspx ht
  • 如何在python中解析ISO格式的日期时间字符串?

    在 pandas 中 我们如何根据这些数据创建日期时间列 df pd DataFrame date 2020 02 04T22 03 44 846000 00 00 print df date 0 2020 02 04T22 03 44 8
  • 使用 VBA 双击单元格以显示 Excel 中链接中的图片

    我有以下功能 如果您将鼠标悬停在图片上 它将显示图片 它非常整洁并且运行良好 但是 我想将其从在其上运行鼠标更改为双击功能 下面是当您将鼠标悬停在单元格上时将显示图片的有效代码 Dim DoOnce As Boolean Public Fu
  • 导航栏中带有大图块或搜索栏的 UIRefreshControl 的动画出现故障

    我有一个嵌入导航控制器的控制器 带有大标题和 UIRefreshControl 当我在 tableView 上进行拉动刷新时 活动指示器的动画非常不稳定 我不知道我的代码是否有不良行为 tableView refreshControl UI
  • 多列数据转换

    我正在从数据源接收数据 在将信息发送到 UI 进行显示之前 我需要先进行数据透视 I am new to concept of pivoting I am not sure how to go about it 问题有两个部分 形成标题 旋