使用Linq构建对象字典并将文本附加到其中一个属性

时间:2013-12-01 06:36:54

标签: c# linq

这是我原来的帖子append string in List contained in a dictionary using LINQ的延续,虽然答案正确,但实际上我的需求略有不同。

简而言之,我有一个字典,其中Key为string类型,Value为string类型。必须将值设置为List,必须将其转换为逗号分隔的字符串。

直到我意识到我确实需要将完整对象存储在我的字典中而不是包含逗号分隔值的字符串,但我的对象的一个​​属性仍然需要将List转换为逗号分隔的字符串。

这是基于我在上一篇文章中提供的原始答案:

Dictionary<string, string> myResult = Mapping.Select(m => m)
   .Select((c, i) => new { Key = c.FieldName, Value = c.Value })
   .GroupBy(o => o.Key, o => o.Value)
   .ToDictionary(grp => grp.Key, grp => 
    string.Join(Environment.NewLine, grp.Where(x => !string.IsNullOrEmpty(x))));

如您所见,根据存储在Mappping List中的对象设置Key和Value。

对象包含在我的Mapping中,定义如下:

public class Field
{
   public string FieldName  { get; set; }
   public string FieldType  { get; set; }
   public string FieldValue { get; set; }
}

表达你想要的东西并不总是那么容易,但我会尽力把它说清楚!

我真正需要的是最终得到一个字典,其中键设置为FieldName,并且值设置为Field对象,但对象的FieldValue需要具有与上述代码中应用的逻辑相同的逻辑,即如果在映射列表中定义了多个相同的FieldName,则FieldValue会附加到自身。

通过查看一些数据可能更容易理解。以下是映射列表在硬编码时的外观:

Mapping.Add(new Field{ FieldName="Name", FieldValue="Thierry", FieldType="1" })
Mapping.Add(new Field{ FieldName="Address", FieldValue="The Plaza", FieldType="2" })
Mapping.Add(new Field{ FieldName="Address", FieldValue="My Road", FieldType="2" })
Mapping.Add(new Field{ FieldName="Address", FieldValue="My Road Again", FieldType="2" })
Mapping.Add(new Field{ FieldName="City", FieldValue="New York", FieldType="1" })
Mapping.Add(new Field{ FieldName="Country", FieldValue="USA", FieldType="1" })

上面代码创建的字典会生成以下内容:

MyResult: Key="Name", Value="Thierry"
MyResult: Key="Address", Value="ThePlaza\r\nMy Road\r\nMy Road Again"
MyResult: Key="City", Value="New York"
MyResult: Key="Country", Value="USA"

我想要的是

MyResult: Key="Name", Field {FieldName="Name", FieldType="1", FieldValue="Thierry"}
MyResult: Key="Address", Field {FieldName="Address", FieldType="2", FieldValue="ThePlaza\r\nMy Road\r\nMy Road Again"}
MyResult: Key="City", Field {FieldName="City", FieldType="1", FieldValue="New York"}
MyResult: Key="Country", Field {FieldName="Country", FieldType="1", FieldValue="USA"}

正如您所看到的,我的字典的键设置为FieldName,并且该值设置为Field对象,但地址只有一个条目(而不是3),并且值已连接!! < / p>

我已经尝试过以下但是a)它不起作用b)我仍然在努力应用于Linq的逻辑所以我再次依靠你聪明的linq家伙来帮助我!

Dictionary<string, Field> uniqueFieldList1 = 
Mapping.Select(m => m)
       .Select((c, i) => new
       {
         Key = c.FieldName,
         Value = new Field()
            {
              FieldName = c.FieldName,
              FieldType = c.FieldType,
              FieldValue = 
              Mapping.Select(m => m)
                     .Select((g, t) => new { Key = g.FieldName, Value = g.FieldValue })
                     .GroupBy(o => o.Key, o => o.Value)
                     .ToDictionary(grp => grp.Key, grp => string.Join(Environment.NewLine, grp.Where(x => !string.IsNullOrEmpty(x))))[c.FieldName]
            }
        })
        .GroupBy(o => o.Key, o => o.Value)
        .ToDictionary(grp => grp.Key, grp => grp.Key);

我的最后一行代码是出错,但我认为它与最后一行有关

.GroupBy(o => o.Key, o => o.Value)
.ToDictionary(grp => grp.Key, grp => grp.Key);

您也可以告诉我,我设置FieldValue的方式是否正确,这是实现此目的的最佳方式吗?

我希望上述内容有道理。

感谢。

Ť

2 个答案:

答案 0 :(得分:2)

按名称对字段进行分组,然后使用聚合字段值从每个组创建新字段。创建字典很简单:

Mapping.GroupBy(f => f.FieldName)
   .Select(g => new Field { 
       FieldName = g.Key,
       FieldType = g.First().FieldType // Note, that I get type from first field
       FieldValue = String.Join(Environment.NewLine, g.Select(f => f.FieldValue))
   })
   .ToDictionary(f => f.FieldName);

我在加入值时没有添加过滤器Where(f => !String.IsNullOrEmpty(f.FieldValue)),因为示例数据中没有空值。

顺便说一句,如果你正在聚合值,那么你可能需要通过其他属性进行分组 - 名称和类型。因为如果您有两个具有相同名称但类型不同的字段,则不会在结果中反映出来。在这种情况下,字典应该在字典中提交哪种类型?

答案 1 :(得分:1)

对于相同的FieldType值,FieldName值是否可以不同?如果没有,你可以使用lazyberezovskys的解决方案。

否则,您需要按FieldNameFieldType进行分组。您可以(例如)为Field设置为null的密钥创建FieldValue个实例:

Mapping.GroupBy(m => new Field
                     {
                         FieldName = m.FieldName,
                         FieldType = m.FieldType
                     })
       .ToDictionary(grp => grp.Key,
                     grp => string.Join(Environment.NewLine,
                                        grp.Select(f => f.FieldValue)));

结果类型为Dictionary<Field, string>,其中键是Field,仅代表FieldNameFieldType,而值只是组合字符串。当然,您还可以为从组密钥重复FieldFieldName的值创建FieldValue个实例。

要使用Field作为字典的键,您应该为GetHashCode类提供适当的EqualsField实现。

如果您不需要字典的查找功能,也可以使用:

Mapping.GroupBy(m => new
                     {
                         m.FieldName,
                         m.FieldType
                     })
       .Select(grp => new Field
                      {
                          FieldName = grp.Key.FieldName,
                          FieldType = grp.Key.FieldType,
                          FieldValue = string.Join(Environment.NewLine,
                                                   grp.Select(f => f.FieldValue))
                      });

这将返回IEnumerable<Field>,其中FieldNameFieldType值不同。