You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#如何实现Dictionary数据拆分行列、对齐算差并导出CSV

C# 实现字典转二维对齐结构方案

核心逻辑设计

覆盖单字典传入、双字典对齐、差值计算全场景,核心处理规则如下:

  • 入参兼容1个或2个Dictionary<string, double>类型数据集,禁止传入空数据集
  • 统一提取全量维度:遍历所有传入字典的键,按-拆分行标识(横杠前半段)、列标识(横杠后半段),对所有行、列标识去重后排序,保证输出结构稳定
  • 跨字典对齐规则:对每个(行标识,列标识)的交叉位,若某字典无对应键,该位置填充double.NaN作为缺失标记,不会出现行列错位
  • 双字典场景自动计算差值:仅当两个字典在同一交叉位都有有效数值时,计算第二个字典值 - 第一个字典值,存在缺失值时差值位同样填充double.NaN
  • 输出结果为平铺的二维字符串数组,可直接写入CSV,无需二次结构转换

可直接复用的实现代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

public static class DictGridConverter
{
    /// <summary>
    /// 将1/2个横杠分隔key的字典转换为对齐的二维结构
    /// </summary>
    /// <param name="dicts">待处理字典集合,数量为1或2</param>
    /// <param name="missingValuePlaceholder">缺失值导出时的占位符,默认为空字符串</param>
    /// <returns>二维字符串数组,第一行为表头,后续为数据行</returns>
    /// <exception cref="ArgumentException">传入字典数量不符合要求时抛出</exception>
    public static string[][] ConvertToGrid(IEnumerable<Dictionary<string, double>> dicts, string missingValuePlaceholder = "")
    {
        var dictList = dicts?.ToList() ?? throw new ArgumentNullException(nameof(dicts));
        var dictCount = dictList.Count;
        if (dictCount is <1 or >2)
            throw new ArgumentException("仅支持传入1个或2个待处理字典");

        // 收集全量行、列标识
        var allRowKeys = new HashSet<string>();
        var allColKeys = new HashSet<string>();
        foreach (var dict in dictList)
        {
            foreach (var key in dict.Keys)
            {
                var keyParts = key.Split('-', 2, StringSplitOptions.RemoveEmptyEntries);
                if (keyParts.Length != 2) continue; // 过滤格式不符合要求的key
                allRowKeys.Add(keyParts[0]);
                allColKeys.Add(keyParts[1]);
            }
        }

        // 排序保证输出顺序稳定
        var sortedRows = allRowKeys.OrderBy(r => r).ToList();
        var sortedCols = allColKeys.OrderBy(c => c).ToList();

        // 生成表头
        var header = new List<string> {"行标识"};
        if (dictCount == 1)
        {
            header.AddRange(sortedCols);
        }
        else
        {
            foreach (var col in sortedCols)
            {
                header.Add($"字典1_{col}");
                header.Add($"字典2_{col}");
                header.Add($"差值_{col}");
            }
        }

        var result = new List<string[]> {header.ToArray()};

        // 逐行生成数据
        foreach (var row in sortedRows)
        {
            var rowData = new List<string> {row};
            foreach (var col in sortedCols)
            {
                var queryKey = $"{row}-{col}";
                double val1 = double.NaN;
                double val2 = double.NaN;

                if (dictList[0].TryGetValue(queryKey, out var v1))
                    val1 = v1;
                if (dictCount == 2 && dictList[1].TryGetValue(queryKey, out var v2))
                    val2 = v2;

                rowData.Add(double.IsNaN(val1) ? missingValuePlaceholder : val1.ToString());
                if (dictCount == 2)
                {
                    rowData.Add(double.IsNaN(val2) ? missingValuePlaceholder : val2.ToString());
                    var diff = double.IsNaN(val1) || double.IsNaN(val2) ? double.NaN : val2 - val1;
                    rowData.Add(double.IsNaN(diff) ? missingValuePlaceholder : diff.ToString());
                }
            }
            result.Add(rowData.ToArray());
        }

        return result.ToArray();
    }

    /// <summary>
    /// 辅助方法:将二维数组直接写入CSV文件
    /// </summary>
    public static void WriteToCsv(string[][] gridData, string savePath, string separator = ",")
    {
        var sb = new StringBuilder();
        foreach (var line in gridData)
        {
            var escapedLine = line.Select(cell =>
            {
                // 处理包含分隔符、引号、换行的内容转义
                if (cell.Contains(separator) || cell.Contains('"') || cell.Contains('\n'))
                    return $"\"{cell.Replace("\"", "\"\"")}\"";
                return cell;
            });
            sb.AppendLine(string.Join(separator, escapedLine));
        }
        File.WriteAllText(savePath, sb.ToString(), Encoding.UTF8);
    }
}

使用示例

// 单字典场景
var dict1 = new Dictionary<string, double>
{
    {"a-b", 1.2}, {"a-c", 3.4}, {"a-d", 5.6}, {"e-b", 7.8}
};
var singleDictGrid = DictGridConverter.ConvertToGrid(new[] {dict1});
DictGridConverter.WriteToCsv(singleDictGrid, "单字典输出.csv");

// 双字典场景
var dict2 = new Dictionary<string, double>
{
    {"a-b", 1.5}, {"a-c", 3.0}, {"e-b", 8.2}, {"e-d", 2.1}
};
var doubleDictGrid = DictGridConverter.ConvertToGrid(new[] {dict1, dict2});
DictGridConverter.WriteToCsv(doubleDictGrid, "双字典对齐输出.csv");

边界场景处理说明

  • 单个字典传入时,自动跳过差值计算逻辑,仅输出基础二维行列结构
  • 两个字典的行、列集合不完全重叠时,自动补全所有缺失维度,不会丢失任意字典的条目
  • 格式不符合x-y规范的键会被自动过滤,可根据需要在代码中增加异常key的日志输出
  • 数值为0的有效条目不会被误判为缺失值,缺失值默认导出为空字符串,可通过入参自定义占位符
  • 自带CSV转义逻辑,单元格内容包含逗号、引号、换行时不会出现CSV格式错乱

内容的提问来源于stack exchange,提问作者Kristielingg

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 14:33:28