C# 使用linq组合两个对象的更好方法?

C# 使用linq组合两个对象的更好方法?,c#,linq,C#,Linq,我们的一些数据不是最干净的。例如,如果一个人以两种不同的方式给出了他们的地址,他可能会出现在输出中两次:一次是RD,另一次是Road 有趣的是,他们一半的数据出现在一个记录中,另一半出现在另一个记录中。所以 Johnny, Larsen Rd, Tuesday, 4 milk bottles Johnny, Larsen Road, Tuesday, 3 milk bottles 约翰尼周二的消费量实际上是7瓶牛奶。我正试图编写一个LINQ,将这两个对象合并在一起,不会有太多的痛苦,但到目前为

我们的一些数据不是最干净的。例如,如果一个人以两种不同的方式给出了他们的地址,他可能会出现在输出中两次:一次是RD,另一次是Road

有趣的是,他们一半的数据出现在一个记录中,另一半出现在另一个记录中。所以

Johnny, Larsen Rd, Tuesday, 4 milk bottles
Johnny, Larsen Road, Tuesday, 3 milk bottles
约翰尼周二的消费量实际上是7瓶牛奶。我正试图编写一个LINQ,将这两个对象合并在一起,不会有太多的痛苦,但到目前为止,我只有这些:

var records = report.GroupBy(r => r.Date)
    .Select(n => new MilkBottleRecord() {
        Name = report.First().Name,
        Address = report.First().Address,
        Date = report.First().Date,
        Bottles = n.Sum(x => x.Bottles),
    });
有什么建议吗

我应该指出,A这不是我们的数据,所以我们不能真正地进行清理,B我们通过CSV而不是SQL查询获取数据


此外,上面查询中唯一相关的信息是日期,因为我在前面的查询中已经将不同的帐户分开。既然这个很好,我觉得不值得您花时间将它包含在这里。

与其使用痛苦的查询,不如检查数据库并合并重复的记录?如果您这样做,您的查询将看起来更好。

与其使用痛苦的编写查询,不如检查数据库并合并重复记录?如果您这样做,您的查询将看起来更好。

履行公司使用软件来修复和规范地址。如果你在做一些专业的事情,你可能会去调查

否则,您可以执行以下操作:

string NormalizeAddress(string str)
{
    // should probably be a bit more intelligent than this, but maybe not.
    str = str.ToUpperInvariant();
    str = str.Replace ("ROAD", "RD");
    return str;
}

var records = report.GroupBy(r =>
                         Tuple.Create(r.Date, NormalizeAddress(r.Address)))
履行公司使用软件修复和规范地址。如果你在做一些专业的事情,你可能会去调查

否则,您可以执行以下操作:

string NormalizeAddress(string str)
{
    // should probably be a bit more intelligent than this, but maybe not.
    str = str.ToUpperInvariant();
    str = str.Replace ("ROAD", "RD");
    return str;
}

var records = report.GroupBy(r =>
                         Tuple.Create(r.Date, NormalizeAddress(r.Address)))

您可以尝试以下方法:

IEqualityComparer<MilkBottleRecord> comparer = /* instantiate a comparer */
var records = report.GroupBy(x => x, comparer)
                    .Select(g => new MilkBottleRecord(g.Key) {
                        Bottles = g.Sum(x => x.Bottles))
                    });

基本思想是:将比较逻辑外部化,创建一个复制构造函数,允许您复制显著信息,然后用总和覆盖瓶子字段。

您可以尝试以下方法:

IEqualityComparer<MilkBottleRecord> comparer = /* instantiate a comparer */
var records = report.GroupBy(x => x, comparer)
                    .Select(g => new MilkBottleRecord(g.Key) {
                        Bottles = g.Sum(x => x.Bottles))
                    });

基本思想是:将比较逻辑外部化,创建一个复制构造函数,允许您复制显著信息,然后用总和覆盖瓶子字段。

如果您无法更改数据结构,那么类似这样的方法如何

var records = report.GroupBy(r => r.Date)
    .Select(n => new MilkBottleRecord(report.First, n.Sum(x => x.Bottles)));
还有一个构造器

MilkBottleReport(MilkBottleReport original, int newBottles); 

如果您不能更改数据结构,那么像

var records = report.GroupBy(r => r.Date)
    .Select(n => new MilkBottleRecord(report.First, n.Sum(x => x.Bottles)));
还有一个构造器

MilkBottleReport(MilkBottleReport original, int newBottles); 

作为你问题的答案——创建一个新的环境,你的LINQ看起来会更好。 但正如archer884所说,LINQ可能会窒息;我还补充说,在不知道进度的情况下处理大量数据是不好的——一条记录一条记录地迭代。
另外:正如zmbq所指出的,将数据清理移到它自己的模块/dll/assembly/machine/process/business。

作为对您问题的回答,创建一个新的程序,您的LINQ看起来会更好。 但正如archer884所说,LINQ可能会窒息;我还补充说,在不知道进度的情况下处理大量数据是不好的——一条记录一条记录地迭代。
另外:正如zmbq所指出的,将数据清理移到它自己的模块/dll/assembly/machine/process/business。

真正的答案是对数据进行清理和规范化。决定地址中使用的是道路/Rd、大道/Av/Ave、街道/St、车道/Dr、车道/Ln的详细说明或缩写类型,然后更改数据以符合您选择的标准并消除重复

答案的另一部分是使用不可变的标识符来区分记录。你可能最终会遇到两个截然不同的人,他们叫约翰尼,住在拉森路。甚至可能是同一条拉森路;约翰和昵称约翰尼很常见,很容易有两个约翰尼路过约翰尼,他们住在拉森路上;他们希望能通过姓氏、地段或公寓号来区分,但如果你认为这些数据中的任何一个是可疑的,那么你仍然有问题。解决方案是一个唯一的标识符,例如帐号,允许您积极区分居住在拉森路的两个不同的叫约翰尼的人,或者相反,识别任何其他唯一标识信息中的差异,否则会导致您将一个人误认为两个人


LINQ并不是万能的,虽然您可以使用LINQ提出一个通用的规范化查询,但我不想站在您后面维护它。还有其他工具可用于将真实世界的数据清理成计算机可以匹配的内容。

真正的答案是清理和规范化数据。决定地址中使用的是道路/Rd、大道/Av/Ave、街道/St、车道/Dr、车道/Ln的详细说明或缩写类型,然后更改数据以符合您选择的标准并消除重复

答案的另一部分是使用不可变的标识符来区分记录。你可能最终会遇到两个截然不同的人,他们叫约翰尼,住在拉森路。甚至可能是同一条拉森路;约翰和昵称约翰尼很常见,很容易有两个约翰尼路过约翰尼,他们住在拉森路上;他们会满怀希望的 我们可能会根据姓氏、地段或公寓号来区分,但如果您认为这些数据中的任何一个是可疑的,那么您仍然存在问题。解决方案是一个唯一的标识符,例如帐号,允许您积极区分居住在拉森路的两个不同的叫约翰尼的人,或者相反,识别任何其他唯一标识信息中的差异,否则会导致您将一个人误认为两个人



LINQ并不是万能的,虽然您可以使用LINQ提出一个通用的规范化查询,但我不想站在您后面维护它。还有其他工具可用于将真实世界的数据清理成计算机可以匹配的东西。

如果对象这么小,这种方法就可以了,但真实的东西比上面的奶瓶记录要大得多,也更复杂。我不确定问题是什么。。。是唯一可互换的单词Rd和Road,还是有一个需要这样工作的单词对列表?在您的查询中,日期似乎是唯一重要的选择器,这意味着在同一天交货的Alice和John将被集中在一起…?然后您可能会考虑如何通过添加一些索引来调整DB。如果有两个不同的Johnny呢?如果名称+地址不再足以知道什么是唯一的,那么这些记录的真正密钥是什么?如果对象这么小,这种方法就可以了,但真正的对象要比上面的MilkBottleRecord大得多,也更复杂。我不确定问题是什么。。。是唯一可互换的单词Rd和Road,还是有一个需要这样工作的单词对列表?在您的查询中,日期似乎是唯一重要的选择器,这意味着在同一天交货的Alice和John将被集中在一起…?然后您可能会考虑如何通过添加一些索引来调整DB。如果有两个不同的Johnny呢?如果名称+地址不再足以知道什么是唯一的,那么这些记录的真正密钥是什么?对不起;这是从CSV加载的:垃圾进来,垃圾出去,把垃圾修好,其他的东西都应该放好+1在尝试从CSV中提取数据之前,您仍然可以查看CSV并合并重复记录。C合并代码将比复杂的查询代码清晰得多。我不会使用LINQ来合并这些记录。结果很糟糕,而且无法维护。如何直接从文本文件合并记录?对不起;这是从CSV加载的:垃圾进来,垃圾出去,把垃圾修好,其他的东西都应该放好+1在尝试从CSV中提取数据之前,您仍然可以查看CSV并合并重复记录。C合并代码将比复杂的查询代码清晰得多。我不会使用LINQ来合并这些记录。结果很糟糕,而且不可能维护。您如何直接从文本文件合并记录?我们很想修复它,但这不是我们的数据。公平地说,您的建议实际上对这种情况很有效。其他案件可能不那么容易处理;这就是为什么我认为对于给定的日期datetime.date field.CASS,最好是基于基本常数,这是经过USPS认证的非常安全的,他们要求提供一些折扣,我推荐它。我工作的大多数客户都使用它。不管是哪种方式,您都希望修复地址、一个聚合组(通过更简单的方式对规范化地址进行写入,如图所示),或者一个自定义比较器(可能会更好地执行内部规范化)。我们很想修复它,但它不是我们的数据。公平地说,您的建议在这种情况下实际上很有效。其他案件可能不那么容易处理;这就是为什么我认为对于给定的日期datetime.date field.CASS,最好是基于基本常数,这是经过USPS认证的非常安全的,他们要求提供一些折扣,我推荐它。我工作的大多数客户都使用它。无论是哪种方式,您都希望修复地址,这是一个聚合组,更易于针对规范化地址进行写入,如图所示,或者一个定制的比较器可能会更好地执行内部规范化。我认为我收到的构造函数建议可能是我能做的最好的,可以使原始版本中荒谬的select语句无效。@archer884:坦白地说,我支持zmbq的解决方案。这是一个数据清理问题,您可能希望在CSV中处理,而不是在C中。但是,如果您将此初始导入视为清理步骤,然后我会使用一个复制构造函数/相等比较器。我认为我收到的构造函数建议可能是我能做的最好的,可以使原始中荒谬的select语句无效。@archer884:坦白地说,我支持zmbq的解决方案。这是一个数据清理问题,您可能希望在CSV中处理,而不是在C中处理。如果您将此初始导入视为清理
然而,在这一步中,我将使用一个复制构造函数/相等比较器;我没有将其包含在样本中,因为样本中只包含一个确定身份的人的记录;我没有把它包括在样本中,因为样本中只包括一个确定身份的人的记录。