Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/282.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 将对象列表转换为表格结构_C#_.net_Linq_Data Structures - Fatal编程技术网

C# 将对象列表转换为表格结构

C# 将对象列表转换为表格结构,c#,.net,linq,data-structures,C#,.net,Linq,Data Structures,我有一个包含此实现的对象列表: class Locations { public string Origin { get; set; } public string Dest { get; set; } public int Total { get; set; } } 我需要以CSV格式输出一个表,该表以行的形式显示起点,以列的形式显示目的地,以及指定的起点和目的地的合计。我的列表中可能有任意数量的位置对象 鉴于我名单中的以下记

我有一个包含此实现的对象列表:

 class Locations
    {
        public string Origin { get; set; }
        public string Dest { get; set; }
        public int Total { get; set; }
    }
我需要以CSV格式输出一个表,该表以行的形式显示起点,以列的形式显示目的地,以及指定的起点和目的地的合计。我的列表中可能有任意数量的位置对象

鉴于我名单中的以下记录:

Origin=A
Dest=B
Total=10

Origin=B
Dest=A
Total=20
我的输出如下所示(带“-”字符表示相同的起点/目的地之间没有总计):

到目前为止,我已经做了以下工作:

1) 遍历列表以输出目的地

2) 遍历列表以输出原点。对于原点,遍历列表以查找与原点相关的每个目标的总数

3) 对下一个原点重复#2


由于行/列数据并不总是匹配,因此我的结果不太合适。有更简单的解决方案吗?

我不确定是否正确理解了您的要求,但这有帮助吗

var destinationGroups = locations
    .GroupBy(l=> l.Dest)
    .Select(grp => new{
        SumTotal = grp.Sum(l => l.Total),
        Destination = grp.Key ,
        CountOrigins = grp.Count()
    });

我不确定我是否正确理解了您的要求,但这有帮助吗

var destinationGroups = locations
    .GroupBy(l=> l.Dest)
    .Select(grp => new{
        SumTotal = grp.Sum(l => l.Total),
        Destination = grp.Key ,
        CountOrigins = grp.Count()
    });
使现代化 在阅读您的更新之后,似乎没有必要求和,因为只有一个对象具有给定的
原点
目标
。在这种情况下,您可以保留收集
位置的代码,执行嵌套的
foreach
,只需使用

var item = locations.FirstOrDefault(l => l.Origin == origin && l.Dest == dest);
var total = item == null ? 0 : item.Total;
原始答案 您可以使用获取所有位置的列表

var locations = new List<Locations>(); // assume it's populated
var places = locations.Select(l => l.Origin)
                      .Concat(locations.Select(l => l.Dest))
                      .Distinct()
                      .OrderBy(s => s); // why not sort it as well
您可以立即看到如何使用此结构轻松构造表。这种方法的主要缺点是它所做的工作比严格必要的要多得多;理论上,我们当然可以在
位置上迭代一次,一边收集信息。对于每对
Origin
Dest
,可以使用

var totals = locations.GroupBy(l => new { l.Origin, l.Dest })
             .ToDictionary(g => Tuple.Create(g.Key.Origin, g.Key.Dest),
                           g => g.Sum(r => r.Total));
此时,我们可以从第一个解决方案中选取一页:

foreach (var origin in places)
{
    foreach (var dest in places)
    {
        var total = totals[Tuple.Create(origin, dest)]; // almost too easy :)
    }
}
使现代化 在阅读您的更新之后,似乎没有必要求和,因为只有一个对象具有给定的
原点
目标
。在这种情况下,您可以保留收集
位置的代码,执行嵌套的
foreach
,只需使用

var item = locations.FirstOrDefault(l => l.Origin == origin && l.Dest == dest);
var total = item == null ? 0 : item.Total;
原始答案 您可以使用获取所有位置的列表

var locations = new List<Locations>(); // assume it's populated
var places = locations.Select(l => l.Origin)
                      .Concat(locations.Select(l => l.Dest))
                      .Distinct()
                      .OrderBy(s => s); // why not sort it as well
您可以立即看到如何使用此结构轻松构造表。这种方法的主要缺点是它所做的工作比严格必要的要多得多;理论上,我们当然可以在
位置上迭代一次,一边收集信息。对于每对
Origin
Dest
,可以使用

var totals = locations.GroupBy(l => new { l.Origin, l.Dest })
             .ToDictionary(g => Tuple.Create(g.Key.Origin, g.Key.Dest),
                           g => g.Sum(r => r.Total));
此时,我们可以从第一个解决方案中选取一页:

foreach (var origin in places)
{
    foreach (var dest in places)
    {
        var total = totals[Tuple.Create(origin, dest)]; // almost too easy :)
    }
}

您的问题似乎与二维矩阵结构(它被称为O/D矩阵)有关,但重要的是不要限制大小。所以,我建议您使用集合构建矩阵结构,以允许不限制大小。我将代码片段放在下面,以演示如何操作。然而,这段代码可能不是最优的,但您可能会得到一些启发

公共类位置
{
公共字符串源{get;set;}
公共字符串Dest{get;set;}
公共布尔等于(其他位置)
{
//...
}
公共覆盖布尔等于(对象对象对象)
{
//...
}
公共覆盖int GetHashCode()
{
//...
}
}
公共类ODM矩阵
{
私有只读哈希集_origins=new HashSet();
私有只读哈希集_dests=new HashSet();
私有只读字典_值=新字典();
公共int此[位置]
{
收到
{
如果(!_值.ContainsKey(位置))
{
设置值(位置,0);
}
返回_值[位置];
}
set{SetValue(位置,值);}
}
私有void SetValue(位置,int值)
{
if(!\u origins.Contains(location.Origin))
_origins.Add(location.Origin);
如果(!\u目的地包含(location.Dest))
_目的地添加(地点目的地);
_值[位置]=值;
}
public int this[字符串原点,字符串目标]
{
获取{返回此[新位置{Origin=Origin,Dest=Dest}];}
设置{this[新位置{Origin=Origin,Dest=Dest}]=value;}
}
公共重写字符串ToString()
{
var content=新的StringBuilder();
//打印目的地标签
内容附录(_dest.Aggregate((x,y)=>x+”,“+y));
foreach(字符串原点在_原点中)
{
//打印原产地标签
内容。追加(来源+“,”);
foreach(字符串dest in_dests)
{
追加(此[来源,目的地]+“,”);
}
content.Remove(content.Length-2,2);
content.AppendLine();
}
返回content.ToString();
}
}
哦,从你最新的问题中,我查到你想要打印原始和目的地的标签。我认为您可以修改ToString方法来显示内容

[更新]
我更新了代码以打印标签。此代码未经测试,因此可能会有问题,也可能不会有问题。

您的问题似乎与二维矩阵结构有关(称为O/D矩阵),但重要的是不要限制大小。所以,我建议您使用集合构建矩阵结构,以允许不限制大小。我将代码片段放在下面,以演示如何操作。然而,这段代码可能不是最优的,但您可能会得到一些启发

公共类位置
{
公共字符串源{get;set;}
公共字符串Dest{get;set;}
公共布尔等于(其他位置)
{
//...
}
公共覆盖布尔等于(对象对象对象)