Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.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
是否可以使用LINQ透视数据?_Linq_Pivot Table - Fatal编程技术网

是否可以使用LINQ透视数据?

是否可以使用LINQ透视数据?,linq,pivot-table,Linq,Pivot Table,我想知道是否可以使用LINQ从以下布局透视数据: CustID | OrderDate | Qty 1 | 1/1/2008 | 100 2 | 1/2/2008 | 200 1 | 2/2/2008 | 350 2 | 2/28/2008 | 221 1 | 3/12/2008 | 250 2 | 3/15/2008 | 2150 变成这样: CustID | Jan- 2008 | Feb- 2008 | Mar - 20

我想知道是否可以使用LINQ从以下布局透视数据:

CustID | OrderDate | Qty
1      | 1/1/2008  | 100
2      | 1/2/2008  | 200
1      | 2/2/2008  | 350
2      | 2/28/2008 | 221
1      | 3/12/2008 | 250
2      | 3/15/2008 | 2150
变成这样:

CustID  | Jan- 2008 | Feb- 2008 | Mar - 2008 |
1       | 100       | 350       |  250
2       | 200       | 221       | 2150

将您的数据按月份分组,然后将其投影到一个新的datatable中,其中包含每个月的列。新表将是您的数据透视表。

类似的内容

List<CustData> myList = GetCustData();

var query = myList
    .GroupBy(c => c.CustId)
    .Select(g => new {
        CustId = g.Key,
        Jan = g.Where(c => c.OrderDate.Month == 1).Sum(c => c.Qty),
        Feb = g.Where(c => c.OrderDate.Month == 2).Sum(c => c.Qty),
        March = g.Where(c => c.OrderDate.Month == 3).Sum(c => c.Qty)
    });
List myList=GetCustData();
var query=myList
.GroupBy(c=>c.CustId)
.选择(g=>new{
CustId=g.Key,
Jan=g.Where(c=>c.OrderDate.Month==1)。Sum(c=>c.Qty),
Feb=g.Where(c=>c.OrderDate.Month==2.Sum(c=>c.Qty),
三月=g.Where(c=>c.OrderDate.Month==3)。总和(c=>c.Qty)
});
Linq中的GroupBy与SQL的工作原理不同。在SQL中,您可以获得键和聚合(行/列形状)。在Linq中,可以将键和任何元素作为键的子元素(层次形状)。若要透视,必须将层次结构投影回您选择的行/列形式。

我使用linq扩展方法回答:

// order s(ource) by OrderDate to have proper column ordering
var r = s.Pivot3(e => e.custID, e => e.OrderDate.ToString("MMM-yyyy")
    , lst => lst.Sum(e => e.Qty));
// order r(esult) by CustID
(+)通用实现
(-)绝对比艾米B的慢


是否有人可以改进我的实现(即该方法对列和行进行排序)?

以下是一种更通用的方法,可以使用LINQ透视数据:

IEnumerable<CustData> s;
var groupedData = s.ToLookup( 
        k => new ValueKey(
            k.CustID, // 1st dimension
            String.Format("{0}-{1}", k.OrderDate.Month, k.OrderDate.Year // 2nd dimension
        ) ) );
var rowKeys = groupedData.Select(g => (int)g.Key.DimKeys[0]).Distinct().OrderBy(k=>k);
var columnKeys = groupedData.Select(g => (string)g.Key.DimKeys[1]).Distinct().OrderBy(k=>k);
foreach (var row in rowKeys) {
    Console.Write("CustID {0}: ", row);
    foreach (var column in columnKeys) {
        Console.Write("{0:####} ", groupedData[new ValueKey(row,column)].Sum(r=>r.Qty) );
    }
    Console.WriteLine();
}

我认为,最简洁的方法是使用查找:

var query =
    from c in myList
    group c by c.CustId into gcs
    let lookup = gcs.ToLookup(y => y.OrderDate.Month, y => y.Qty)
    select new
    {
        CustId = gcs.Key,
        Jan = lookup[1].Sum(),
        Feb = lookup[2].Sum(),
        Mar = lookup[3].Sum(),
    };

这是最有效的方法:

检查以下方法。而不是在每个月的每次客户组中迭代

var query = myList
    .GroupBy(c => c.CustId)
    .Select(g => {
        var results = new CustomerStatistics();
        foreach (var customer in g)
        {
            switch (customer.OrderDate.Month)
            {
                case 1:
                    results.Jan += customer.Qty;
                    break;
                case 2:
                    results.Feb += customer.Qty;
                    break;
                case 3:
                    results.March += customer.Qty;
                    break;
                default:
                    break;
            }
        }
        return  new
        {
            CustId = g.Key,
            results.Jan,
            results.Feb,
            results.March
        };
    });
或者这个:

var query = myList
    .GroupBy(c => c.CustId)
    .Select(g => {
        var results = g.Aggregate(new CustomerStatistics(), (result, customer) => result.Accumulate(customer), customerStatistics => customerStatistics.Compute());
        return  new
        {
            CustId = g.Key,
            results.Jan,
            results.Feb,
            results.March
        };
    });
完整解决方案:

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

namespace ConsoleApp
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            IEnumerable<CustData> myList = GetCustData().Take(100);

            var query = myList
                .GroupBy(c => c.CustId)
                .Select(g =>
                {
                    CustomerStatistics results = g.Aggregate(new CustomerStatistics(), (result, customer) => result.Accumulate(customer), customerStatistics => customerStatistics.Compute());
                    return new
                    {
                        CustId = g.Key,
                        results.Jan,
                        results.Feb,
                        results.March
                    };
                });
            Console.ReadKey();
        }

        private static IEnumerable<CustData> GetCustData()
        {
            Random random = new Random();
            int custId = 0;
            while (true)
            {
                custId++;
                yield return new CustData { CustId = custId, OrderDate = new DateTime(2018, random.Next(1, 4), 1), Qty = random.Next(1, 50) };
            }
        }

    }
    public class CustData
    {
        public int CustId { get; set; }
        public DateTime OrderDate { get; set; }
        public int Qty { get; set; }
    }
    public class CustomerStatistics
    {
        public int Jan { get; set; }
        public int Feb { get; set; }
        public int March { get; set; }
        internal CustomerStatistics Accumulate(CustData customer)
        {
            switch (customer.OrderDate.Month)
            {
                case 1:
                    Jan += customer.Qty;
                    break;
                case 2:
                    Feb += customer.Qty;
                    break;
                case 3:
                    March += customer.Qty;
                    break;
                default:
                    break;
            }
            return this;
        }
        public CustomerStatistics Compute()
        {
            return this;
        }
    }
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
名称空间控制台
{
内部课程计划
{
私有静态void Main(字符串[]args)
{
IEnumerable myList=GetCustData().Take(100);
var query=myList
.GroupBy(c=>c.CustId)
.选择(g=>
{
CustomerStatistics结果=g.Aggregate(新CustomerStatistics(),(结果,客户)=>result.acculate(客户),CustomerStatistics=>CustomerStatistics.Compute());
还新
{
CustId=g.Key,
结果:1月,
结果:2月,
结果,三月
};
});
Console.ReadKey();
}
私有静态IEnumerable GetCustData()
{
随机=新随机();
int custId=0;
while(true)
{
custId++;
收益返回新的CustData{CustId=CustId,OrderDate=newdatetime(2018,random.Next(1,4),1),Qty=random.Next(1,50)};
}
}
}
公共类数据
{
public int CustId{get;set;}
public DateTime OrderDate{get;set;}
公共整数数量{get;set;}
}
公共类客户统计
{
公共整数Jan{get;set;}
公共int Feb{get;set;}
公共整数{get;set;}
内部客户统计累积(客户数据)
{
开关(customer.OrderDate.Month)
{
案例1:
一月+=客户数量;
打破
案例2:
二月+=客户数量;
打破
案例3:
三月+=客户数量;
打破
违约:
打破
}
归还这个;
}
公共客户统计计算()
{
归还这个;
}
}
}

我无法想象这将如何工作,但我很好奇,请求您包含一些示例代码。在应用透视之前,列表必须是IEnumerable吗?或者也可以在EF的IQueryable上执行此操作(而不必在内存中具体化列表)?@RobVermeulen我可以将该查询转换为sql,因此我希望EF也能够将其转换。试试吧,我想?我测试过了,有点效果。尽管SQLProfiler显示EF不会将其转换为(快速)透视查询,而是转换为几个较慢的子查询。
var query = myList
    .GroupBy(c => c.CustId)
    .Select(g => {
        var results = g.Aggregate(new CustomerStatistics(), (result, customer) => result.Accumulate(customer), customerStatistics => customerStatistics.Compute());
        return  new
        {
            CustId = g.Key,
            results.Jan,
            results.Feb,
            results.March
        };
    });
using System;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleApp
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            IEnumerable<CustData> myList = GetCustData().Take(100);

            var query = myList
                .GroupBy(c => c.CustId)
                .Select(g =>
                {
                    CustomerStatistics results = g.Aggregate(new CustomerStatistics(), (result, customer) => result.Accumulate(customer), customerStatistics => customerStatistics.Compute());
                    return new
                    {
                        CustId = g.Key,
                        results.Jan,
                        results.Feb,
                        results.March
                    };
                });
            Console.ReadKey();
        }

        private static IEnumerable<CustData> GetCustData()
        {
            Random random = new Random();
            int custId = 0;
            while (true)
            {
                custId++;
                yield return new CustData { CustId = custId, OrderDate = new DateTime(2018, random.Next(1, 4), 1), Qty = random.Next(1, 50) };
            }
        }

    }
    public class CustData
    {
        public int CustId { get; set; }
        public DateTime OrderDate { get; set; }
        public int Qty { get; set; }
    }
    public class CustomerStatistics
    {
        public int Jan { get; set; }
        public int Feb { get; set; }
        public int March { get; set; }
        internal CustomerStatistics Accumulate(CustData customer)
        {
            switch (customer.OrderDate.Month)
            {
                case 1:
                    Jan += customer.Qty;
                    break;
                case 2:
                    Feb += customer.Qty;
                    break;
                case 3:
                    March += customer.Qty;
                    break;
                default:
                    break;
            }
            return this;
        }
        public CustomerStatistics Compute()
        {
            return this;
        }
    }
}