如何查询数据列表以使行成为列

时间:2013-12-17 06:01:01

标签: linq

我有一个如下所示的数据列表

Item    Vendor  Compliance  Status

I1      V1          C1          Y
I1      V1          C2          N
I1      V1          C3          Y
I1      V2          C1          Y
I1      V2          C2          Y
I2      V1          C3          Y

如何查询以使其成为

Item    Vendor  C1  C2  C3

I1      V1       Y  N   Y    
I1      V2       Y  Y   -
I2      V1       -  -   Y

虽然合规性可能有很多,但不一定只有C1,C2,C3。

3 个答案:

答案 0 :(得分:2)

我将欺骗@Serv并使用他用于定义数据的部分代码(叹息 - 是的,我很懒惰。)

要处理dynamic方面的许多合规性,您可以使用ExpandoObject。您需要做的就是获取所有现有的合规性类型,并为每种类型为您的对象分配属性。

void Main()
{
    var content = new List<Content>()
    {
        new Content("I1", "V1", "C1", true),
        new Content("I1", "V1", "C2", false),
        new Content("I1", "V1", "C3", true),
        new Content("I1", "V2", "C1", true),
        new Content("I1", "V2", "C2", true),
        new Content("I2", "V1", "C3", true),
        new Content("I2", "V1", "C4", true)
    };

    var compliances = content.Select(c=>c.Compliance).Distinct();
    var temp = content.GroupBy (c => new {Item = c.Item, Vendor = c.Vendor});
    var results = temp.Select (t => 
    {
        dynamic result = new ExpandoObject();
        result.Item = t.Key.Item;
        result.Vendor = t.Key.Vendor;
        foreach(var compliance in compliances)
        {
            var isCompliant = t.Any(x => x.Compliance == compliance && x.Status.GetValueOrDefault());
            ((IDictionary<String, Object>)result).Add(compliance, isCompliant);
        }
        return result;
    }).Dump();
}

public class Content
{
    public Content(string item, string vendor, string compliance, bool? status)
    {
        Item = item; Vendor = vendor; Compliance = compliance; Status = status;
    }

    public string Item { get; set; }
    public string Vendor { get; set; }
    public string Compliance { get; set; }
    public bool? Status { get; set; }
}

结果:

Results

修改

要在合规性不存在时获取null而不是false,请使用此代码foreach循环:

var isCompliant = t.FirstOrDefault(x => x.Compliance == compliance); 
((IDictionary<String, Object>)result).Add(compliance, isCompliant == null ? null : isCompliant.Status);

结果如下:

Results after edit.

答案 1 :(得分:1)

我很确定通过这样做违反了十几个良好编程原则,但我认为这个解决方案有效。我所做的是在Linqpad中创建了一个类,其中Status是bool类型(我很懒)。

这是整个片段,因此您可以重现它:

void Main()
{
    var content = new List<Content>()
    {
      new Content("I1", "V1", "C1", true),
      new Content("I1", "V1", "C2", false),
      new Content("I1", "V1", "C3", true),
      new Content("I1", "V2", "C1", true),
      new Content("I1", "V2", "C2", true),
      new Content("I2", "V1", "C3", true)
    };

    var temp = content.GroupBy (c => new {Item = c.Item, Vendor = c.Vendor});
    var result = temp.Select (t => new 
                      {
                          Item = t.Key.Item,
                          Vendor = t.Key.Vendor,
                          C1 = content.Where(x => x.Item == t.Key.Item && x.Vendor == t.Key.Vendor && x.Compliance == "C1").Select (x => x.Status),
                          C2 = content.Where(x => x.Item == t.Key.Item && x.Vendor == t.Key.Vendor && x.Compliance == "C2").Select (x => x.Status),
                          C3 = content.Where(x => x.Item == t.Key.Item && x.Vendor == t.Key.Vendor && x.Compliance == "C3").Select (x => x.Status)
                      }).Dump();

}

// Define other methods and classes here
public class Content
{
    public Content(string item, string vendor, string compliance, bool? status)
    {
      Item = item; Vendor = vendor; Compliance = compliance; Status = status;
    }

    public string Item { get; set; }
    public string Vendor { get; set; }
    public string Compliance { get; set; }
    public bool? Status { get; set; }

}

这是输出,可以提供您的预期:

dummy description

答案 2 :(得分:1)

鉴于您的数据为:

class Data
{
    public int Item {get; set;}
    public int Vendor {get; set;}
    public int Compliance {get; set;}
    public bool Status {get; set;}
}

Data[] data = 
{
    new Data {Item=1, Vendor=1, Compliance=1, Status=true},
    new Data {Item=1, Vendor=1, Compliance=2, Status=false},
    new Data {Item=1, Vendor=1, Compliance=3, Status=true},
    new Data {Item=1, Vendor=2, Compliance=1, Status=true},
    new Data {Item=1, Vendor=2, Compliance=2, Status=true},
    new Data {Item=2, Vendor=1, Compliance=3, Status=true}
};

可能的解决方案可能

var compliance = data.Select(d => d.Compliance).Distinct().ToList();

var result = data.GroupBy(d => new {d.Item, d.Vendor})
                 .Select(g => new 
                 {
                     Item = g.Key.Item,
                     Vendor = g.Key.Vendor,
                     Compliance = (from c in compliance
                                   join cs in g.Select(x => new {x.Compliance, x.Status}) on c equals cs.Compliance into j
                                   from cs in j.DefaultIfEmpty()
                                   select new { Compliance = c, Value = cs!=null ? cs.Status : (bool?)null })

                 });

导致

enter image description here

对于不同Compliance值的任意数字,您不能使用强类型结果,但可以使用{{1将Join的结果转换为Dictionary<string, bool?>方法。