I have the below scenario
List<Class> Classes = new List<Class>();
Class c1 = new Class() { ClassID = 1, Name = "Class1", Abbreviation = "CLS1" }; Classes.Add(c1);
Class c2 = new Class() { ClassID = 2, Name = "Class2", Abbreviation = "CLS2" }; Classes.Add(c2);
Class c3 = new Class() { ClassID = 3, Name = "Class3", Abbreviation = "CLS3" }; Classes.Add(c3);
List<ClassCode> ClassCodes = new List<ClassCode>();
ClassCode cc1 = new ClassCode() { ClassID = 1, ClassCodeID = 1, Code = "CC1", Description = "CCD1", Class = c1 }; ClassCodes.Add(cc1);
ClassCode cc2 = new ClassCode() { ClassID = 1, ClassCodeID = 2, Code = "CC2", Description = "CCD2", Class = c1 }; ClassCodes.Add(cc2);
ClassCode cc3 = new ClassCode() { ClassID = 2, ClassCodeID = 3, Code = "CC3", Description = "CCD3", Class = c2 }; ClassCodes.Add(cc3);
ClassCode cc4 = new ClassCode() { ClassID = 2, ClassCodeID = 4, Code = "CC4", Description = "CCD4", Class = c2 }; ClassCodes.Add(cc4);
ClassCode cc5 = new ClassCode() { ClassID = 3, ClassCodeID = 5, Code = "CC5", Description = "CCD5", Class = c3 }; ClassCodes.Add(cc5);
ClassCode cc6 = new ClassCode() { ClassID = 3, ClassCodeID = 6, Code = "CC6", Description = "CCD6", Class = c3 }; ClassCodes.Add(cc6);
I am trying to use Linq to transpose the above data in the below format
Class1 | CLS1 | Class2 | CLS2 | Class3 | CLS3 - Columns
---------------------------------------------------------------------------
CCD1CCD2 | CC1CC2 | CCD3CCD4 | CC3CC4 | CCD5CCD6 | CC4CC5 - Row
Columns headers are values of Name (Class) and Abbreviation (Class) on the basis of group by on ClassID (ClassCode)
Value is concatination of Code (ClassCode) and Description (ClassCode) - Map is Code goes to Abbreviation Column and Description goes to Name Column
DataTable is a fit when you want to create properties at runtime - any other option will be appreciated.
Please help!!
You are not explaining why you are doing this.
There might be other ways of achieving what you want.
Anyway, the following code should work.
It produces a DataTable, which I think is a good fit for this:
var dt = new System.Data.DataTable("Transpose");
foreach (var c in Classes)
{
var dc1 = new System.Data.DataColumn(c.Name, typeof(string));
var dc2 = new System.Data.DataColumn(c.Abbreviation, typeof(string));
dc1.ExtendedProperties.Add("ID", c.ClassID);
dc2.ExtendedProperties.Add("ID", c.ClassID);
dt.Columns.AddRange(new System.Data.DataColumn[] { dc1, dc2 } );
}
var dr = dt.NewRow();
for (int i = 0; i < dt.Columns.Count; i++)
{
var col = dt.Columns[i];
dr[i++] = ClassCodes.Where(cc => cc.ClassID == (int)col.ExtendedProperties["ID"])
.Select(cc => cc.Description)
.Aggregate((first, next) => first + next);
col = dt.Columns[i];
dr[i] = ClassCodes.Where(cc => cc.ClassID == (int)col.ExtendedProperties["ID"])
.Select(cc => cc.Code)
.Aggregate((first, next) => first + next);
}
dt.Rows.Add(dr);
Related
I have list of objects as described below:
List<Maths> mObjs = new List<Maths>();
mObjs.Add(new Maths{ Name = "Jack", M1 = 10, M2 = 5, M3 = 0, M4 = 2, M5 =1 });
mObjs.Add(new Maths { Name = "Jill", M1 = 2, M2 = 3, M3 = 4, M4 = 1, M5 = 0 });
mObjs.Add(new Maths { Name = "Michel", M1 = 12, M2 = 15, M3 = 10, M4 = 12, M5 = 11 });
Now I need to calculated the total aggregated value for all three people.
I need to get the below results, probably a new other class
List<Results> mRes = new List<Results>();
public class Results{
public string Name { get; set; }
public int TotalValue { get; set; }
}
mRes.Name = "M1"
mRes.TotalValue = 24;
mRes.Name = "M2"
mRes.TotalValue = 23;
mRes.Name = "M3"
mRes.TotalValue = 14;
mRes.Name = "M4"
mRes.TotalValue = 15;
mRes.Name = "M5"
mRes.TotalValue = 12;
How can I get this data from mObjs using linq query? I know we can do it using for, but want to know if there are any better ways to get this using linq query because that reduces lines of code and I have similar requirements in many other places and dont want to write number of foreach or fors every time.
You can use a pre selection list to list both the name and the field to select
var lookups = new Dictionary<string,Func<Maths,int>> {
{"M1", x => x.M1 },
{"M2", x => x.M2 },
{"M3", x => x.M3 },
{"M4", x => x.M4 },
{"M5", x => x.M5 },
};
Then you can simply do
var mRes = dlookups.Select(x => new Results {
Name= x.Key,
TotalValue = mObjs.Sum(x.Value)
}).ToList();
BEGIN UPDATED*
In response to comments
The lambda expression is just a function from your source class to an int.
For example
class Sub1 {
string M3 {get;set;}
int M4 {get;set;}
}
class Math2 {
string Name {get;set;}
string M1 {get;set;}
string M2 {get;set;}
Sub1 Sub {get;set;}
}
var lookups = new Dictionary<string,Func<Math2,int>> {
{ "M1", x => int.Parse(x.M1) },
{ "M2", x => int.Parse(x.M2) },
{ "M3", x => int.Parse(x.Sub.M3) },
{ "M4", x => int.Parse(x.Sub.M4} }
};
Or if you want to put a little error checking in, you can either use functions or embed the code.
int GetInt(string source) {
if (source == null) return 0;
int result;
return int.TryParse(source, out result) ? result : 0;
}
var lookups = new Dictionary<string,Func<Math2,int>> {
{ "M1", x => {
int result;
return x == null ? 0 : (int.TryParse(x,out result) ? result : 0);
},
{ "M2", x => GetInt(x) },
{ "M3", x => x.Sub == null ? 0 : GetInt(x.Sub.M3) },
{ "M4", x => x.Sub == null ? 0 : x.Sub.M4}
};
END UPDATED
If you want to go further you could use reflection to build the lookups dictionary.
Here is a helper function that will generate the lookups for all Integer properties of a class.
public Dictionary<string,Func<T,int>> GenerateLookups<T>() where T: class {
// This just looks for int properties, you could add your own filter
var properties = typeof(T).GetProperties().Where(pi => pi.PropertyType == typeof(int));
var parameter = Expression.Parameter(typeof(T));
return properties.Select(x => new {
Key = x.Name,
Value = Expression.Lambda<Func<T,int>>(Expression.Property(parameter,x),parameter).Compile()
}).ToDictionary (x => x.Key, x => x.Value);
}
Now you can just do:
var mRes=GenerateLookups<Maths>().Select( x => new Results
{
Name = x.Key,
TotalValue = mObjs.Sum(x.Value)
}).ToList();
Not very smart but efficient and readable:
int m1Total= 0;
int m2Total= 0;
int m3Total= 0;
int m4Total= 0;
int m5Total= 0;
foreach(Maths m in mObjs)
{
m1Total += m.M1;
m2Total += m.M2;
m3Total += m.M3;
m4Total += m.M4;
m5Total += m.M5;
}
List<Results> mRes = new List<Results>
{
new Results{ Name = "M1", TotalValue = m1Total },
new Results{ Name = "M2", TotalValue = m2Total },
new Results{ Name = "M3", TotalValue = m3Total },
new Results{ Name = "M4", TotalValue = m4Total },
new Results{ Name = "M5", TotalValue = m5Total },
};
Result:
Name: "M1" TotalValue: 24
Name: "M2" TotalValue: 23
Name: "M3" TotalValue: 14
Name: "M4" TotalValue: 15
Name: "M5" TotalValue: 12
Edit: since you've explicitly asked for LINQ, if the properties are always these five i don't see why you need to use LINQ at all. If the number can change i would use a different structure.
You could for example use
a single List<Measurement> instead of multiple properties where Measurement is another class that stores the name and the value or you could use
a Dictionary<string, int> for efficient lookup.
You can try out some thing like this :
mRes.Add(new Results() { Name = "M1", TotalValue = mObjs.Sum(x => x.M1) });
To programmatically iterate through all the class properties, you might need to employ reflection.
I was trying to change the table names in the entity model or database but the old names are already use in many places in the application. Is there any way to auto reflect renamed entities or tables in the LINQ query or code.
Let say I have tables tblDepartment, tblEmployee and tblEmployeeDepartment. These tables are used in the code(LINQ) on many places. I like to change these tables names to Department, Employee and EmployeeDepartment. So, is there anyway to auto reflect name in LINQ or code when I change table names either using Database First or Model First approach.
P.S. The application is based on .Net 3.5
Working With linq and Entity Framework plus excel reports|Enjoy
public static string strMessage = "";
public SchoolEntities dbContext;
public string login(string strUsername, string strPassword)
{
dbContext = new SchoolEntities();
var linqQuery = from User in dbContext.People
where User.FirstName == strUsername && User.LastName == strPassword
select User;
if (linqQuery.Count() == 1)
{
strMessage = "Good";
}
else
{
strMessage = "Bad";
}
return strMessage;
}
public Object LoadPersonDetails()
{
dbContext = new SchoolEntities();
//DataTable dtPerson = new DataTable();
var linqQuery = from users in dbContext.People
select users;
//List<Person> Users = linqQuery.ToList();
//dtPerson = linqQuery.ToList();
return linqQuery;
}
public void InsertPerson(string strLName, string strFName, string strHireDate, string EnrollmentDate)
{
dbContext = new SchoolEntities();
Person NewPerson = dbContext.People.Create();
NewPerson.LastName = strLName;
NewPerson.FirstName = strFName;
NewPerson.HireDate = Convert.ToDateTime(strHireDate);
NewPerson.EnrollmentDate = Convert.ToDateTime(EnrollmentDate);
dbContext.People.Add(NewPerson);
dbContext.SaveChanges();
}
public void DeleteUser(int intPersonID)
{
//dbContext = new SchoolEntities();
using (dbContext = new SchoolEntities())
{
Person Person = dbContext.People.Where(c => c.PersonID == intPersonID).FirstOrDefault();
if (Person != null)
{
dbContext.People.Remove(Person);
dbContext.SaveChanges();
}
}
}
public void ModifyPerson(int intPersonID, string strLName, string strFName, string strHireDate, string EnrollmentDate)
{
var UpdatePerson = dbContext.People.FirstOrDefault(s => s.PersonID == intPersonID);
UpdatePerson.LastName = strLName;
UpdatePerson.FirstName = strFName;
UpdatePerson.HireDate = Convert.ToDateTime(strHireDate);
UpdatePerson.EnrollmentDate = Convert.ToDateTime(EnrollmentDate);
dbContext.SaveChanges();
}
private Excel.Application XApp = null; //Creates the Excel Document
private Excel.Workbook XWorkbook = null; //create the workbook in the recently created document
private Excel.Worksheet XWorksheet = null; //allows us to work with current worksheet
private Excel.Range XWorkSheet_range = null; // allows us to modify cells on the sheet
public void Reports()
{
dbContext = new SchoolEntities();
var linqQuery = (from users in dbContext.StudentGrades
group users by new { users.EnrollmentID, users.CourseID, users.StudentID, users.Grade }
into UserGroup
orderby UserGroup.Key.CourseID ascending
select new { UserGroup.Key.EnrollmentID, UserGroup.Key.CourseID, UserGroup.Key.StudentID, UserGroup.Key.Grade }).ToList();
var RatingAverage = dbContext.StudentGrades.Average(r => r.Grade);
var GradeSum = dbContext.StudentGrades.Sum(r => r.Grade);
/*var linqQuery = (from users in dbContext.StudentGrades
orderby users.CourseID descending
select users).ToList();*/
//Array Motho = linqQuery.ToArray();
XApp = new Excel.Application();
XApp.Visible = true;
XWorkbook = XApp.Workbooks.Add(1);
XWorksheet = (Excel.Worksheet)XWorkbook.Sheets[1];
//Create column headers
XWorksheet.Cells[2, 1] = "EnrollmentID";
XWorksheet.Cells[2, 2] = "CourseID";
XWorksheet.Cells[2, 3] = "StudentID";
XWorksheet.Cells[2, 4] = "Grade";
//XWorksheet.Cells[2, 5] = "Enrollment Date";
int row = 3;
foreach (var Mothos in linqQuery)
{
XWorksheet.Cells[row, 1] = Mothos.EnrollmentID.ToString();
XWorksheet.Cells[row, 2] = Mothos.CourseID.ToString();
XWorksheet.Cells[row, 3] = Mothos.StudentID.ToString();
XWorksheet.Cells[row, 4] = Mothos.Grade.ToString();
row++;
}
int rows = linqQuery.Count();
XWorksheet.Cells[rows + 4, 3] = "Grades Average";
XWorksheet.Cells[rows + 4, 4] = RatingAverage.Value.ToString();
XWorksheet.Cells[rows + 5, 3] = "Grades Sum";
XWorksheet.Cells[rows + 5, 4] = GradeSum.Value.ToString();
//XWorkSheet_range.ColumnWidth = 30;
//XWorksheet.Cells.AutoFit();
}
Working with xml | add, modify and delete xml data
string conn = "E:/School/Development Sftware/2014/ReadWriteUpdateDeleteXML/DataService/Profiles.xml";
public string InsertProfile(string fname, string lname, string phone, string gender)
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(conn);
XmlElement subRoot = xmlDoc.CreateElement("Profile");
//add first name
XmlElement appendedElementFname = xmlDoc.CreateElement("FirstName");
XmlText xmlTextFname = xmlDoc.CreateTextNode(fname.Trim());
appendedElementFname.AppendChild(xmlTextFname);
subRoot.AppendChild(appendedElementFname);
xmlDoc.DocumentElement.AppendChild(subRoot);
//add last name
XmlElement appendedElementLname = xmlDoc.CreateElement("LastName");
XmlText xmlTextLname = xmlDoc.CreateTextNode(lname.Trim());
appendedElementLname.AppendChild(xmlTextLname);
subRoot.AppendChild(appendedElementLname);
xmlDoc.DocumentElement.AppendChild(subRoot);
//add phone
XmlElement appendedElementPhone = xmlDoc.CreateElement("Phone");
XmlText xmlTextPhone = xmlDoc.CreateTextNode(phone.Trim());
appendedElementPhone.AppendChild(xmlTextPhone);
subRoot.AppendChild(appendedElementPhone);
xmlDoc.DocumentElement.AppendChild(subRoot);
//add gender
XmlElement appendedElementGender = xmlDoc.CreateElement("Gender");
XmlText xmlTextGender = xmlDoc.CreateTextNode(gender.Trim());
appendedElementGender.AppendChild(xmlTextGender);
subRoot.AppendChild(appendedElementGender);
xmlDoc.DocumentElement.AppendChild(subRoot);
xmlDoc.Save(conn);
return "Profile Saved";
}
public DataSet LoadXML()
{
DataSet dsLog = new DataSet();
dsLog.ReadXml(conn);
return dsLog;
}
public string DeleteProfile(string fname)
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(conn);
//XmlNode nodeToDelete = xmlDoc.SelectSingleNode("/Profiles/Profile[#FirstName=" + fname + "]");
//if (nodeToDelete != null)
//{
// nodeToDelete.ParentNode.RemoveChild(nodeToDelete);
//}
//xmlDoc.Save("C:/Users/Shazzy/Documents/Visual Studio 2010/Projects/ReadWriteUpdateDeleteXML/DataService/Profiles.xml");
//return "Deleted";
foreach (XmlNode node in xmlDoc.SelectNodes("Profiles/Profile"))
{
if (node.SelectSingleNode("FirstName").InnerText == fname)
{
node.ParentNode.RemoveChild(node);
}
}
xmlDoc.Save(conn);
return "Deleted";
}
public string ModifyProfile(string fname, string lname, string phone, string gender)
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(conn);
foreach (XmlNode node in xmlDoc.SelectNodes("Profiles/Profile"))
{
if (node.SelectSingleNode("FirstName").InnerText == fname)
{
node.SelectSingleNode("FirstName").InnerText = fname;
node.SelectSingleNode("LastName").InnerText = lname;
node.SelectSingleNode("Phone").InnerText = phone;
node.SelectSingleNode("Gender").InnerText = gender;
}
}
xmlDoc.Save(conn);
return "Updated";
}
Working with edm and Excel-grouped report
public void Function_Create_Sales()
{
DBContext = new PubsEntities();
var linqStores = from Sales in DBContext.sales
orderby Sales.stor_id
select Sales;
var lstStore = linqStores.ToList();
Excel.Application xlApp = new Excel.Application();
xlApp.Visible = true;
Excel.Workbook xlBook = xlApp.Workbooks.Add(1);
Excel.Worksheet xlSheet = (Excel.Worksheet)xlBook.Worksheets[1];
int GroupTotal = 0;
int GrandTotal = 0;
int ExcelRow = 5;
string intTemp = lstStore[0].stor_id;
xlSheet.Cells[4, 1] = lstStore[0].stor_id;
//Create column headers
xlSheet.Cells[1, 1] = "Sales Grouped By Store";
xlSheet.Cells[3, 1] = "Group header";
xlSheet.Cells[3, 2] = "Store ID";
xlSheet.Cells[3, 3] = "Order Number";
xlSheet.Cells[3, 4] = "Order Date";
xlSheet.Cells[3, 5] = "Quantity";
xlSheet.Cells[3, 6] = "payments";
xlSheet.Cells[3, 7] = "title ID";
for (int count = 0; count < lstStore.Count; count++)
{
if (intTemp == lstStore[count].stor_id)
{
xlSheet.Cells[ExcelRow, 2] = lstStore[count].stor_id.ToString();
xlSheet.Cells[ExcelRow, 3] = lstStore[count].ord_date.ToString();
xlSheet.Cells[ExcelRow, 4] = lstStore[count].qty.ToString();
xlSheet.Cells[ExcelRow, 5] = lstStore[count].payterms.ToString();
xlSheet.Cells[ExcelRow, 5] = lstStore[count].title_id.ToString();
ExcelRow++;
GroupTotal++;
GrandTotal++;
}
else
{
xlSheet.Cells[ExcelRow, 5] = "Total for: " + intTemp + " = " + GroupTotal.ToString();
ExcelRow++;
intTemp = lstStore[count].stor_id;
xlSheet.Cells[ExcelRow, 1] = lstStore[count].stor_id;
count--;
GroupTotal = 0;
ExcelRow++;
}
}
xlSheet.Cells[ExcelRow, 5] = "Total for: " + intTemp + " = " + GroupTotal.ToString();
ExcelRow++;
xlSheet.Cells[ExcelRow, 5] = "Grand Total = " + GrandTotal.ToString();
xlSheet.Rows.Columns.AutoFit();
}
I have a collection of items that contain an Enum (TypeCode) and a User object, and I need to flatten it out to show in a grid. It's hard to explain, so let me show a quick example.
Collection has items like so:
TypeCode | User
---------------
1 | Don Smith
1 | Mike Jones
1 | James Ray
2 | Tom Rizzo
2 | Alex Homes
3 | Andy Bates
I need the output to be:
1 | 2 | 3
Don Smith | Tom Rizzo | Andy Bates
Mike Jones | Alex Homes |
James Ray | |
I've tried doing this using foreach, but I can't do it that way because I'd be inserting new items to the collection in the foreach, causing an error.
Can this be done in Linq in a cleaner fashion?
I'm not saying it is a great way to pivot - but it is a pivot...
// sample data
var data = new[] {
new { Foo = 1, Bar = "Don Smith"},
new { Foo = 1, Bar = "Mike Jones"},
new { Foo = 1, Bar = "James Ray"},
new { Foo = 2, Bar = "Tom Rizzo"},
new { Foo = 2, Bar = "Alex Homes"},
new { Foo = 3, Bar = "Andy Bates"},
};
// group into columns, and select the rows per column
var grps = from d in data
group d by d.Foo
into grp
select new {
Foo = grp.Key,
Bars = grp.Select(d2 => d2.Bar).ToArray()
};
// find the total number of (data) rows
int rows = grps.Max(grp => grp.Bars.Length);
// output columns
foreach (var grp in grps) {
Console.Write(grp.Foo + "\t");
}
Console.WriteLine();
// output data
for (int i = 0; i < rows; i++) {
foreach (var grp in grps) {
Console.Write((i < grp.Bars.Length ? grp.Bars[i] : null) + "\t");
}
Console.WriteLine();
}
Marc's answer gives sparse matrix that can't be pumped into Grid directly.
I tried to expand the code from the link provided by Vasu as below:
public static Dictionary<TKey1, Dictionary<TKey2, TValue>> Pivot3<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(
x => new
{
X = x.Key,
Y = source.GroupBy(key2Selector).Select(
z => new
{
Z = z.Key,
V = aggregate(from item in source
where key1Selector(item).Equals(x.Key)
&& key2Selector(item).Equals(z.Key)
select item
)
}
).ToDictionary(e => e.Z, o => o.V)
}
).ToDictionary(e => e.X, o => o.Y);
}
internal class Employee
{
public string Name { get; set; }
public string Department { get; set; }
public string Function { get; set; }
public decimal Salary { get; set; }
}
public void TestLinqExtenions()
{
var l = new List<Employee>() {
new Employee() { Name = "Fons", Department = "R&D", Function = "Trainer", Salary = 2000 },
new Employee() { Name = "Jim", Department = "R&D", Function = "Trainer", Salary = 3000 },
new Employee() { Name = "Ellen", Department = "Dev", Function = "Developer", Salary = 4000 },
new Employee() { Name = "Mike", Department = "Dev", Function = "Consultant", Salary = 5000 },
new Employee() { Name = "Jack", Department = "R&D", Function = "Developer", Salary = 6000 },
new Employee() { Name = "Demy", Department = "Dev", Function = "Consultant", Salary = 2000 }};
var result5 = l.Pivot3(emp => emp.Department, emp2 => emp2.Function, lst => lst.Sum(emp => emp.Salary));
var result6 = l.Pivot3(emp => emp.Function, emp2 => emp2.Department, lst => lst.Count());
}
* can't say anything about the performance though.
You can use Linq's .ToLookup to group in the manner you are looking for.
var lookup = data.ToLookup(d => d.TypeCode, d => d.User);
Then it's a matter of putting it into a form that your consumer can make sense of. For instance:
//Warning: untested code
var enumerators = lookup.Select(g => g.GetEnumerator()).ToList();
int columns = enumerators.Count;
while(columns > 0)
{
for(int i = 0; i < enumerators.Count; ++i)
{
var enumerator = enumerators[i];
if(enumator == null) continue;
if(!enumerator.MoveNext())
{
--columns;
enumerators[i] = null;
}
}
yield return enumerators.Select(e => (e != null) ? e.Current : null);
}
Put that in an IEnumerable<> method and it will (probably) return a collection (rows) of collections (column) of User where a null is put in a column that has no data.
I guess this is similar to Marc's answer, but I'll post it since I spent some time working on it. The results are separated by " | " as in your example. It also uses the IGrouping<int, string> type returned from the LINQ query when using a group by instead of constructing a new anonymous type. This is tested, working code.
var Items = new[] {
new { TypeCode = 1, UserName = "Don Smith"},
new { TypeCode = 1, UserName = "Mike Jones"},
new { TypeCode = 1, UserName = "James Ray"},
new { TypeCode = 2, UserName = "Tom Rizzo"},
new { TypeCode = 2, UserName = "Alex Homes"},
new { TypeCode = 3, UserName = "Andy Bates"}
};
var Columns = from i in Items
group i.UserName by i.TypeCode;
Dictionary<int, List<string>> Rows = new Dictionary<int, List<string>>();
int RowCount = Columns.Max(g => g.Count());
for (int i = 0; i <= RowCount; i++) // Row 0 is the header row.
{
Rows.Add(i, new List<string>());
}
int RowIndex;
foreach (IGrouping<int, string> c in Columns)
{
Rows[0].Add(c.Key.ToString());
RowIndex = 1;
foreach (string user in c)
{
Rows[RowIndex].Add(user);
RowIndex++;
}
for (int r = RowIndex; r <= Columns.Count(); r++)
{
Rows[r].Add(string.Empty);
}
}
foreach (List<string> row in Rows.Values)
{
Console.WriteLine(row.Aggregate((current, next) => current + " | " + next));
}
Console.ReadLine();
I also tested it with this input:
var Items = new[] {
new { TypeCode = 1, UserName = "Don Smith"},
new { TypeCode = 3, UserName = "Mike Jones"},
new { TypeCode = 3, UserName = "James Ray"},
new { TypeCode = 2, UserName = "Tom Rizzo"},
new { TypeCode = 2, UserName = "Alex Homes"},
new { TypeCode = 3, UserName = "Andy Bates"}
};
Which produced the following results showing that the first column doesn't need to contain the longest list. You could use OrderBy to get the columns ordered by TypeCode if needed.
1 | 3 | 2
Don Smith | Mike Jones | Tom Rizzo
| James Ray | Alex Homes
| Andy Bates |
#Sanjaya.Tio I was intrigued by your answer and created this adaptation which minimizes keySelector execution. (untested)
public static Dictionary<TKey1, Dictionary<TKey2, TValue>> Pivot3<TSource, TKey1, TKey2, TValue>(
this IEnumerable<TSource> source
, Func<TSource, TKey1> key1Selector
, Func<TSource, TKey2> key2Selector
, Func<IEnumerable<TSource>, TValue> aggregate)
{
var lookup = source.ToLookup(x => new {Key1 = key1Selector(x), Key2 = key2Selector(x)});
List<TKey1> key1s = lookup.Select(g => g.Key.Key1).Distinct().ToList();
List<TKey2> key2s = lookup.Select(g => g.Key.Key2).Distinct().ToList();
var resultQuery =
from key1 in key1s
from key2 in key2s
let lookupKey = new {Key1 = key1, Key2 = key2}
let g = lookup[lookupKey]
let resultValue = g.Any() ? aggregate(g) : default(TValue)
select new {Key1 = key1, Key2 = key2, ResultValue = resultValue};
Dictionary<TKey1, Dictionary<TKey2, TValue>> result = new Dictionary<TKey1, Dictionary<TKey2, TValue>>();
foreach(var resultItem in resultQuery)
{
TKey1 key1 = resultItem.Key1;
TKey2 key2 = resultItem.Key2;
TValue resultValue = resultItem.ResultValue;
if (!result.ContainsKey(key1))
{
result[key1] = new Dictionary<TKey2, TValue>();
}
var subDictionary = result[key1];
subDictionary[key2] = resultValue;
}
return result;
}
I have 2 objects (lists loaded from XML) report and database (showed bellow in code) and i should analyse them and mark items with 0, 1, 2, 3 according to some conditions
TransactionResultCode = 0; // SUCCESS (all fields are equivalents: [Id, AccountNumber, Date, Amount])
TransactionResultCode = 1; // Exists in report but Not in database
TransactionResultCode = 2; // Exists in database but Not in report
TransactionResultCode = 3; // Field [Id] are equals but other fields [AccountNumber, Date, Amount] are different.
I'll be happy if somebody could found time to suggest how to optimize some queries.
Bellow is the code:
THANK YOU!!!
//TransactionResultCode = 0 - SUCCESS
//JOIN on all fields
var result0 = from d in database
from r in report
where (d.TransactionId == r.MovementID) &&
(d.TransactionAccountNumber == long.Parse(r.AccountNumber)) &&
(d.TransactionDate == r.MovementDate) &&
(d.TransactionAmount == r.Amount)
orderby d.TransactionId
select new TransactionList()
{
TransactionId = d.TransactionId,
TransactionAccountNumber = d.TransactionAccountNumber,
TransactionDate = d.TransactionDate,
TransactionAmount = d.TransactionAmount,
TransactionResultCode = 0
};
//*******************************************
//JOIN on [Id] field
var joinedList = from d in database
from r in report
where d.TransactionId == r.MovementID
select new TransactionList()
{
TransactionId = d.TransactionId,
TransactionAccountNumber = d.TransactionAccountNumber,
TransactionDate = d.TransactionDate,
TransactionAmount = d.TransactionAmount
};
//Difference report - database
var onlyReportID = report.Select(r => r.MovementID).Except(joinedList.Select(d => d.TransactionId));
//TransactionResultCode = 1 - Not Found in database
var result1 = from o in onlyReportID
from r in report
where (o == r.MovementID)
orderby r.MovementID
select new TransactionList()
{
TransactionId = r.MovementID,
TransactionAccountNumber = long.Parse(r.AccountNumber),
TransactionDate = r.MovementDate,
TransactionAmount = r.Amount,
TransactionResultCode = 1
};
//*******************************************
//Difference database - report
var onlyDatabaseID = database.Select(d => d.TransactionId).Except(joinedList.Select(d => d.TransactionId));
//TransactionResultCode = 2 - Not Found in report
var result2 = from o in onlyDatabaseID
from d in database
where (o == d.TransactionId)
orderby d.TransactionId
select new TransactionList()
{
TransactionId = d.TransactionId,
TransactionAccountNumber = d.TransactionAccountNumber,
TransactionDate = d.TransactionDate,
TransactionAmount = d.TransactionAmount,
TransactionResultCode = 2
};
//*******************************************
var qwe = joinedList.Select(j => j.TransactionId).Except(result0.Select(r => r.TransactionId));
//TransactionResultCode = 3 - Transaction Results are different (Amount, AccountNumber, Date, )
var result3 = from j in joinedList
from q in qwe
where j.TransactionId == q
select new TransactionList()
{
TransactionId = j.TransactionId,
TransactionAccountNumber = j.TransactionAccountNumber,
TransactionDate = j.TransactionDate,
TransactionAmount = j.TransactionAmount,
TransactionResultCode = 3
};
you may try something like below:
public void Test()
{
var report = new[] {new Item(1, "foo", "boo"), new Item(2, "foo2", "boo2"), new Item(3, "foo3", "boo3")};
var dataBase = new[] {new Item(1, "foo", "boo"), new Item(2, "foo22", "boo2"), new Item(4, "txt", "rt")};
Func<Item, bool> inBothLists = (i) => report.Contains(i) && dataBase.Contains(i);
Func<IEnumerable<Item>, Item, bool> containsWithID = (e, i) => e.Select(_ => _.ID).Contains(i.ID);
Func<Item, int> getCode = i =>
{
if (inBothLists(i))
{
return 0;
}
if(containsWithID(report, i) && containsWithID(dataBase, i))
{
return 3;
}
if (report.Contains(i))
{
return 2;
}
else return 1;
};
var result = (from item in dataBase.Union(report) select new {Code = getCode(item), Item = item}).Distinct();
}
public class Item
{
// You need also to override Equals() and GetHashCode().. I omitted them to save space
public Item(int id, string text1, string text2)
{
ID = id;
Text1 = text1;
Text2 = text2;
}
public int ID { get; set; }
public string Text1 { get; set; }
public string Text2 { get; set; }
}
Note that you need to either implement Equals() for you items, or implement an IEqualityComparer<> and feed it to Contains() methods.
I try make table where i keep children-parent data. Ofc root of parents is "0" and here in table can by many roots. When i try make this work i got error.
Unable to create a constant value of type 'Projekty03.ViewsModels.ParagrafViewModel'. Only primitive types ('such as Int32, String, and Guid') are supported in this context.
public ViewResult Index()
{
List<ParagrafViewModel> _paragrafparent = new List<ParagrafViewModel>();
_paragrafparent.Add(new ParagrafViewModel { ParagrafID = 0, ParagrafNazwa = "Root" });
var _paragrafparent2 = from pr in paragrafRepository.All
orderby pr.ParagrafID
select new ParagrafViewModel
{
ParagrafID = pr.ParagrafID,
ParagrafNazwa = pr.ParagrafNazwa
};
var _paragrafparent3 = _paragrafparent.Concat(_paragrafparent2).AsEnumerable();
var paragraf = from par in paragrafRepository.All
join rodzic_p in _paragrafparent3
on par.ParagrafParent equals rodzic_p.ParagrafID
orderby par.ParagrafParent, par.ParagrafID
select new ParagrafViewModel
{
ParagrafID = par.ParagrafID,
ParagrafNazwa = par.ParagrafNazwa,
ParagrafParent = par.ParagrafParent,
ParagrafCzynny = par.ParagrafCzynny,
ParagrafWplyw = par.ParagrafWplyw,
ParagrafParentNazwa = rodzic_p.ParagrafNazwa
};
return View(paragraf);
}
I believe is sht wrong with my poor magic LINQ think. How resolve this ?
Ok here is a answer for my own question. Im sure is not a pretty solution but ...
public ViewResult Index()
{
List<ParagrafViewModel> _paragrafparent = new List<ParagrafViewModel>();
_paragrafparent.Add(new ParagrafViewModel { ParagrafID = 0, ParagrafNazwa = "Root", ParagrafCzynny=false, });
var _paragrafparent2 = from pr in paragrafRepository.AllIncluding(paragraf => paragraf.WniosekPodzial)
orderby pr.ParagrafID
select new ParagrafViewModel
{
ParagrafID = pr.ParagrafID,
ParagrafNazwa = pr.ParagrafNazwa,
ParagrafParent = pr.ParagrafParent,
ParagrafCzynny = pr.ParagrafCzynny,
ParagrafWplyw = pr.ParagrafWplyw,
WniosekPodzialNazwa = pr.WniosekPodzial.WniosekPodzialNazwa
};
var _paragrafparent3 = _paragrafparent.Concat(_paragrafparent2).AsEnumerable();
var paragrafModel = from par in _paragrafparent3
join rodzic_p in _paragrafparent3
on par.ParagrafParent equals rodzic_p.ParagrafID
orderby par.ParagrafParent, par.ParagrafID
select new ParagrafViewModel
{
ParagrafID = par.ParagrafID,
ParagrafNazwa = par.ParagrafNazwa,
ParagrafParent = par.ParagrafParent,
ParagrafCzynny = par.ParagrafCzynny,
ParagrafWplyw = par.ParagrafWplyw,
ParagrafParentNazwa = rodzic_p.ParagrafNazwa,
WniosekPodzialNazwa = par.WniosekPodzialNazwa
};
return View(paragrafModel);
}