اندازهی قلم متن
تخمین مدت زمان مطالعهی مطلب:
دو دقیقه
اگر به قسمت اول «تهیه گزارشات Crosstab به کمک LINQ» دقت کرده باشید، یک مشکل کوچک دارد و آن هم لزوم مشخص سازی دقیق ستونهایی است که میخواهیم در گزارش ظاهر شوند. مثلا دقیقا مشخص کنیم که نام واحد چیست یا دقیقا روز را مشخص کنیم. این مورد برای گزارشهای کوچک مشکلی ندارد؛ ولی اگر همان مثال دوم را در نظر گرفته و بازه را کمی بیشتر کنیم، مثلا یک ماه، آن وقت باید حداقل 30 بار بنویسیم Day1IsPresent تا ... Day30IsPresent و یا اگر بازهی گزارشگیری به اختیار کاربر باشد آن وقت چه باید کرد؟ مثلا یکبار 7 روز پایان ماه را انتخاب کند، یکبار 14 روز را، شاید یک بار هم مثلا 90 روز را مد نظر داشته باشد (تعداد ستونها متغیر باشد یا به عبارتی Dynamic Crosstab نیاز است ایجاد شود).
برای حل این مساله، میتوان از متد الحاقی زیر از سایت extensionmethod.net کمک گرفت:
using System;
using System.Collections.Generic;
using System.Linq;
namespace PivotExtensions
{
public static class Ext
{
public static Dictionary<TKey1, Dictionary<TKey2, TValue>>
Pivot<TSource, TKey1, TKey2, TValue>
(
this IEnumerable<TSource> source,
Func<TSource, TKey1> key1Selector,
Func<TSource, TKey2> key2Selector,
Func<IEnumerable<TSource>, TValue> aggregate
)
{
return source.GroupBy(key1Selector)
.Select(
key1Group => new
{
Key = key1Group.Key,
Value = key1Group.GroupBy(key2Selector)
.Select(
key2Group => new
{
K = key2Group.Key,
V = aggregate(key2Group)
})
.ToDictionary(e => e.K, o => o.V)
})
.ToDictionary(e => e.Key, o => o.Value);
}
}
}
در این متد:
key1Selector مشخص کننده ستونهای ثابت و مشخص سمت راست یا چپ (بر اساس جهت صفحه) گزارش است. در سیستمهای مختلف این ستونها نامهایی مانند keyColumn ، leftColumn و Row Heading ممکن است داشته باشند.
key2Selector ستونهای پویای گزارش را تشکیل میدهد. در سایر سیستمها این پارامتر، pivotNameColumn ،VariableColumn ، topField و یا Column Heading هم نامیده میشود.
Aggregate در اینجا مشخص میکند که مقادیر ستونهای پویای یاد شده چگونه باید محاسبه شوند.
با توجه به این متد، برای نمونه جهت حل مثال اول قسمت قبل خواهیم داشت:
var list = ExpenseDataSource.ExpensesDataSource();
var pivotList = list.Pivot(
x =>
new
{
x.Date.Year,
x.Date.Month
},
x1 => x1.Department,
x2 => x2.Sum(x => x.Expenses));
با خروجی
فایل LINQPad آن از اینجا قابل دریافت است.
و برای حل مثال دوم قسمت قبل میتوان نوشت:
var list2 = StudentsStatDataSource.CreateWeeklyReportDataSource();
var lst = list2.Pivot(
x =>
new
{
x.Id,
x.Name
},
x1 => "Day " + x1.Date.Day,
x2 => x2.First().IsPresent);
با خروجی
فایل LINQPad آن از اینجا قابل دریافت است.