I have a class like as follows:
public class ActualClass
{
public string BookName { get; set; }
public string IssuerName { get; set; }
public DateTime DateOfIssue { get; set; }
public bool Status { get; set; }
}
It has following data in the table:
I would like to group them by IssuerName and DateOfIssue for the following viewModel class:
public class ViewModel
{
public string IssuerName { get; set; }
public DateTime DateOfIssue { get; set; }
public List<string> Books { get; set; }
}
And data will be displayed as follows: (Screenshot data will be replaced by the previous table data after successful grouping)
Special attention: Is there anything wrong in my ViewModel according to my expectation?
I tried a lot after following some stackoverflow answers but none did work for me. Any help will be highly appreciated.
The code I have tried:
var viewmodel = from b in db.BookIssues
group b by new
{
b.IssuerName,
b.DateOfIssue
}
into g
select new ViewModel()
{
Name = g.key.IssuerName,
DateOfIssue = g.Key.DateOfIssue,
Books = g.ToList() //Actually this line of code is not working
};
Books = g.ToList() //Actually this line of is not working
Probably because Books property is type of List<string>, not List<ActualClass>.
Can you please try this query, I added b.Select(bn => bn.BookName).ToList() to extract only names of books:
var books = new List<ActualClass>
{
new ActualClass { BookName = "A", DateOfIssue = new DateTime(2015, 10, 10, 10, 10, 0), IssuerName = "1" },
new ActualClass { BookName = "B", DateOfIssue = new DateTime(2015, 10, 10, 10, 10, 0), IssuerName = "1" },
new ActualClass { BookName = "C", DateOfIssue = new DateTime(2015, 10, 10, 10, 10, 0), IssuerName = "1" },
new ActualClass { BookName = "D", DateOfIssue = new DateTime(2015, 10, 10, 10, 10, 0), IssuerName = "2" },
new ActualClass { BookName = "E", DateOfIssue = new DateTime(2015, 10, 10, 12, 10, 0), IssuerName = "2" },
new ActualClass { BookName = "F", DateOfIssue = new DateTime(2015, 10, 10, 12, 10, 0), IssuerName = "2" }
};
var result = books.GroupBy(x => new { x.IssuerName, x.DateOfIssue })
.Select(b => new ViewModel
{
Books = b.Select(bn => bn.BookName).ToList(),
// Accessing to DateOfIssue and IssuerName from Key.
DateOfIssue = b.Key.DateOfIssue,
IssuerName = b.Key.IssuerName
});
I grouped by: x.IssuerName, x.DateOfIssue. I did that by passing anonymous type in GroupBy() with following manner: x => new { x.IssuerName, x.DateOfIssue }.
Now they are in key and you can access to IssuerName and DateOfIssue from KEY in SELECT statement like in following: b.Key.IssuerName and b.Key.DateOfIssue.
if you need to select list of books from group result, you need Books = v.Select(c=>c.BookName).ToList() also note that in case of you have time in issue date time you may need to group by only the date part using EntityFunctions.TruncateTime function. if you only storing date only then you can ignore this function.
var viewmodel = db.BookIssues.GroupBy(x=>new {IssuerName =x.IssuerName, DateOfIssue=EntityFunctions.TruncateTime(x.DateOfIssue) })
.Select(v=>new ViewModel(){IssuerName =v.Key.IssuerName, DateOfIssue = v.Key.DateOfIssue, Books = v.Select(c=>c.BookName).ToList() })
.ToList();
Related
Incoming list
var list = new List<Franchise>()
{
new Franchise()
{Id = 10, Name = "Franchise1", Code= "DD1", IsDomestic= 1, ParentCompanyId=1, GroupId=100 },
new Franchise()
{Id = 10, Name = "Franchise1", Code= "DD1", IsDomestic= 1, ParentCompanyId=2, GroupId=100 },
new Franchise()
{Id = 10, Name = "Franchise1", Code= "DD1", IsDomestic= 1, ParentCompanyId=3, GroupId=200 },
new Franchise()
{Id = 15, Name = "Franchise5", Code= "FD1", IsDomestic= 0, ParentCompanyId=4, GroupId=300 },
new Franchise()
{Id = 15, Name = "Franchise5", Code= "FD1", IsDomestic= 0, ParentCompanyId=3, GroupId=300 },
new Franchise()
{Id = 15, Name = "Franchise5", Code= "FD1", IsDomestic= 0, ParentCompanyId=2, GroupId=400 },
};
I want this to be transformed to list of the class below using LINQ
public class FranchiseNew
{
public int Id { get; set; }
public string Name{ get; set; }
public int[] CategoryIds { get; set; }
public int[] DivisionIds { get; set; }
public int IsDomestic{ get; set; }
}
output - one row per franchise with ParentCompanyIds and GroupIds in arrays
var list = new List<Franchise>()
{
new Franchise()
{Id = 10, Name = "Franchise1", Code= "DD1", IsDomestic= 1, ParentCompanyIds=[1, 2, 3], GroupIds = [100, 200 ]},
new Franchise()
{Id = 15, Name = "Franchise2", Code= "FD1", IsDomestic= 0, ParentCompanyIds=[4, 3, 2], GroupIds = [300, 400] }
};
What is the efficient LINQ query to achieve this? Thanks in advance.
You can try like below:
var collectionGroup = list.GroupBy(x => new { x.Name, x.Id, x.Code, x.IsDomestic }).ToList();
var result = collectionGroup.Select(x => new FranchiseNew
{
Id = x.Key.Id,
Name = x.Key.Name,
Code = x.Key.Code,
IsDomestic = x.Key.IsDomestic,
CategoryIds = x.GroupBy(s => s.ParentCompanyId).Select(y => y.Key).ToArray(),
DivisionIds = x.GroupBy(s => s.GroupId).Select(y => y.Key).ToArray()
}).ToList();
And in you're FranchiseNew model, add Code field.
I'm working on an ASP.NET API and I'm having some issuses retrieving a jagged array of different derived object from a base class.
So I have this Base class:
public class BaseContract
{
public int ID { get; set; }
public enum ContractTypes
{
A,
B
}
public ContractTypes contractType;
public string provider { get; set; }
public string user { get; set; }
public enum OfficeLocations
{
A,
B,
C
}
public OfficeLocations office_location;
public DateTime startDate { get; set; }
public DateTime finishDate { get; set; }
}
And then 4 more classes deriving from this:
public class class1 : BaseContract
{
public enum ProductTypes {
A,
B,
C
}
public ProductTypes productType;
}
And like that i have 4 classes.
Before going into getting the data from the DB i'm filling the classes with some random data manually:
public class ContractsController : ApiController
{
BaseContract[][] contracts = new BaseContract[][]{
new class1[]
{
new class1 {
ID=12412341,
contractType = BaseContract.ContractTypes.A,
productType= Protection_automobile.ProductTypes.B,
startDate= new DateTime(2014, 3, 15),
finishDate= new DateTime(2014, 4, 11),
office_location=BaseContract.OfficeLocations.A,
provider="abc"},
new class1 {
ID=52412341,
contractType = BaseContract.ContractTypes.B,
productType= Protection_automobile.ProductTypes.C,
startDate= new DateTime(2015, 7, 24),
finishDate= new DateTime(2015, 9, 2),
office_location=BaseContract.OfficeLocations.C,
provider="wer"}
},
new class2[]
{
new class2{
ID=22374341,
contractType= BaseContract.ContractTypes.A,
productType = Protection_biens.ProductTypes.B,
startDate = new DateTime(2015,2,2),
finishDate =new DateTime(2015,4,17),
office_location = BaseContract.OfficeLocations.B,
provider= "wer"
},
new class2{
ID=12374659,
contractType = BaseContract.ContractTypes.A,
productType = Protection_biens.ProductTypes.A,
startDate = new DateTime(2015,7,1),
finishDate = new DateTime(2015, 5,30),
office_location = BaseContract.OfficeLocations.A,
provider = "abc"
},
new class2{
ID=12374659,
contractType = BaseContract.ContractTypes.B,
productType = Protection_biens.ProductTypes.A,
startDate = new DateTime(2015,8,2),
finishDate = new DateTime(2015, 5,30),
office_location = BaseContract.OfficeLocations.C,
provider = "abc"
}
},
new class3[]
{
new class3{
ID=32378659,
contractType = BaseContract.ContractTypes.A,
productType = Responsabilite_civile.ProductTypes.A,
startDate = new DateTime(2014,8,2),
finishDate = new DateTime(2015, 1,8),
office_location = BaseContract.OfficeLocations.A,
provider = "abc"
},
new class3{
ID=42395634,
contractType = BaseContract.ContractTypes.A,
productType = Responsabilite_civile.ProductTypes.B,
startDate = new DateTime(2015,7,16),
finishDate = new DateTime(2015, 8,8),
office_location = BaseContract.OfficeLocations.B,
provider = "wer"
},
new class3{
ID=42305635,
contractType = BaseContract.ContractTypes.A,
productType = Responsabilite_civile.ProductTypes.A,
startDate = new DateTime(2015,9,29),
finishDate = new DateTime(2015, 10,6),
office_location = BaseContract.OfficeLocations.B,
provider = "abc"
},
},
new class4[]
{
new class4{
ID=14385634,
contractType = BaseContract.ContractTypes.B,
productType = Protection_persones.ProductTypes.B,
startDate = new DateTime(2015,8,4),
finishDate = new DateTime(2015, 8,9),
office_location = BaseContract.OfficeLocations.A,
provider = "wer"
},
new class4{
ID=14385635,
contractType = BaseContract.ContractTypes.B,
productType = Protection_persones.ProductTypes.B,
startDate = new DateTime(2015,9,11),
finishDate = new DateTime(2015, 9,27),
office_location = BaseContract.OfficeLocations.A,
provider = "abc"
}
}
};
class1[] pContracts = new class1[]{
new class1{
ID=14385634,
contractType = BaseContract.ContractTypes.A,
productType = Protection_persones.ProductTypes.B,
startDate = new DateTime(2015,8,4),
finishDate = new DateTime(2015, 8,9),
office_location = BaseContract.OfficeLocations.A,
provider = "wer"
},
new class1{
ID=14385635,
contractType = BaseContract.ContractTypes.B,
productType = Protection_persones.ProductTypes.A,
startDate = new DateTime(2015,9,11),
finishDate = new DateTime(2015, 9,27),
office_location = BaseContract.OfficeLocations.A,
provider = "abc"
}
};
As you can see, I have a jagged array, and then a simple array.
When i try to get the simple array data as IEnumerable<class1> it works.
But when i try to get the jagged array as IEnumerable<IEnumerable<BaseContract>> it throws an error .
public IEnumerable<class1> GetAllContracts()
{
return pContracts;
}
public IEnumerable<IEnumerable<BaseContract>> getcontracts(){
return contracts;
}
Should I change my jagged array data structure? Or what is the correct wat to retrieve that jagged array?
Thank you.
I have a list of Person and a list of BirthDates and I would like to intersect person.BirthYear with BirthDates.Year
Intersects seems to need both lists to be of same type so my question is how to have a func or so which will allow to me write my own custom matching logic?
You can perform a Join which doesn't needs both sequences to be of same type.
This answer should help you with the syntax.
Here is code snippet for your case:
using System;
using System.Linq;
namespace Intersects
{
class Person
{
public string Name { get; set; }
public DateTime BirthDate { get; set; }
}
class Program
{
static void Main(string[] args)
{
var persons = new[]
{
new Person() {Name = "Jack", BirthDate = new DateTime(1990, 1, 1)},
new Person() {Name = "Joe", BirthDate = new DateTime(1970, 9, 9)},
new Person() {Name = "Ivan", BirthDate = new DateTime(1991, 2, 2)},
};
var birthDates = new[]
{
new DateTime(1990, 1, 1),
new DateTime(1991, 2, 2),
new DateTime(1991, 3, 3),
};
var joined = from p in persons
join bd in birthDates
on p.BirthDate.Year equals bd.Year // Your own custom logic
select p;
foreach (var person in joined)
{
Console.WriteLine(person.Name);
}
// Output:
//Jack
//Ivan
//Ivan
}
}
}
suppose that I have this List of Employees representing a table of employees.
public class Employee
{
public string Name { get; set; }
public string Department { get; set; }
public string Function { get; set; }
public decimal Salary { get; set; }
public DateTime EntryDate { get; set; }
public static List<Employee> GetEmployeesList()
{
return new List<Employee>() {
new Employee() { EntryDate = new DateTime(2011, 05, 01), Name = "Fons", Department = "Finance", Function = "Trader", Salary = 6500 },
new Employee() { EntryDate = new DateTime(2013, 05, 02), Name = "Mary", Department = "Finance", Function = "BusinessAnalyst", Salary = 2500 },
new Employee() { EntryDate = new DateTime(2012, 04, 03), Name = "Alex", Department = "Finance", Function = "Trader", Salary = 2100 },
new Employee() { EntryDate = new DateTime(2013, 05, 04), Name = "Jim", Department = "R&D", Function = "Trainer", Salary = 3300 },
new Employee() { EntryDate = new DateTime(2010, 06, 05), Name = "Ellen", Department = "Dev", Function = "Developer", Salary = 2500 },
new Employee() { EntryDate = new DateTime(2000, 09, 06), Name = "Mike", Department = "Dev", Function = "Consultant", Salary = 5100 },
new Employee() { EntryDate = new DateTime(1999, 03, 07), Name = "Jack", Department = "R&D", Function = "Developer", Salary = 6100 },
new Employee() { EntryDate = new DateTime(1989, 01, 08), Name = "Demy", Department = "Dev", Function = "Consultant", Salary = 3300 }};
}
}
I want to be able to select only desired columns to be displayed.
Someting like :
public static List<Employee> SelectColumnsFromTable(List<Employee> employees, int[] selectedColumns)
{
// only select colums 1, 3 and 4
}
I have seen that it is possible with SQL and GridView, but in my case, the result will be printed on the console.
Is it possible using C# and Linq ?
As I understand the question, it is important to select specific properties of a class based on their index. If the relevant indices are provided to you by the user, you can use reflection to access the properties dynamically. The key points are Type.GetProperties and PropertyInfo.GetValue. I've put together a small sample to demonstrate:
using System;
using System.Collections.Generic;
using System.Linq;
public class Employee
{
public int Id {get; set;}
public string FirstName { get; set;}
public string LastName {get; set;}
}
public class Test
{
private static string[] GetColumnValues(Employee emp, params int[] cols)
{
var props = emp.GetType().GetProperties();
var values = new List<string>();
foreach(var i in cols)
{
if (i >= 0 && i < props.Length)
{
object value = props[i].GetValue(emp, null);
values.Add(value == null ? string.Empty : value.ToString());
}
}
return values.ToArray();
}
public static void Main()
{
var emp = new Employee() { Id = 1, FirstName = "John", LastName = "Smith" };
var values = GetColumnValues(emp, 0, 2);
Console.WriteLine(string.Join("\t", values));
}
}
Please note that referencing the properties by their index might not be very deterministic of you change the implementation later on. So selecting by the property's name might be more stable. Also, the column selector function GetColumnValues does not return Employees, but the values as a string array so you can use it in String.Join. You can use the function in Linq:
var rows = from x in listOfEmps select GetColumnValues(x, 0, 2);
foreach(var row in rows)
Console.WriteLine(string.Join("\t", row));
var items = (from i in v.db.DatabaseName
orderby i.EmpID descending
select new {i.Name, i.Function,i.Salary}).ToList();
var list = dt.AsEnumerable()
.Where(row => (int)row["demoid"] > 5)//your condition here
.Select(row => new
{
demoid = Convert.ToInt32(row["demoid"]),
demoname = row["demoname"] != null ?
row["demoname"].ToString() :
String.Empty
}).ToList();
Or you can define class:
public class myClass
{
public int demoid;
public string demoname;
}
and then:
List<myClass> list = dt.AsEnumerable()
.Where(row => (int)row["demoid"] > 5)
.Select(row => new myClass
{
demoid = Convert.ToInt32(row["demoid"]),
demoname = row["demoname"] != null ?
row["demoname"].ToString() :
String.Empty
}).ToList<myClass>();
this is selecting a particular value to a list. However you can use IList<myClass> classcollection= new List<myClass>(); and then add the particular list to class1 based on condition.
Note: here class collection can hold multiple list as u want the columns 1,3,4
I would like to remove duplicate rows by their values from sub list using LINQ syntax. Below I attached code which does that by different way.
xxxxx xxxxxx xxxxxxx xxxxxxxxxxx xxxxxxxxxxxxxx xxxxxxxxxxxx xxxxxxxxxx xxxxxxxxxxxxxxxxxx
List<ZRowCollection> zListCollection = new List<ZRowCollection>();
zListCollection = zListCollection.OrderBy(p => p.P).ToList();
int i1 = 1;
foreach (var item in zListCollection.ToList())
{
var subList1 = item.XRowModified.Select(p => p).ToList();
foreach (var item2 in zListCollection.Skip(i1).ToList())
{
var subList2 = item2.XRowModified.Select(p => p).ToList();
int i = 0;
foreach (var item3 in subList1)
{
var t2 = subList2.Select(p => p.Average).ToList();
decimal average = t2[i];
if (item3.Average == average)
{
i++;
}
else break;
}
if (i == item2.XRowModified.Count)
{
zListCollection.Remove(item2);
}
}
i1++;
}
properties
class XRowModified
{
public decimal Id { get; set; }
public decimal Open { get; set; }
public decimal High { get; set; }
public decimal Low { get; set; }
public decimal Close { get; set; }
public DateTime Time { get; set; }
public decimal Average { get; set; }
}
class ZRowCollection
{
public ZRowCollection()
{
this.XRowModified = new HashSet<XRowModified>();
}
public int P { get; set; }
public int High { get; set; }
public int Low { get; set; }
public virtual ICollection<XRowModified> XRowModified { get; set; }
}
expected input/output,
as a comparer column Average in List<XRowModified>
List<ZRowCollection> zListInput = new List<ZRowCollection>(){
new ZRowCollection(){P = 0,High = 4,Low = 0, XRowModified = new List<XRowModified>(){
new XRowModified(){ Id = 1550, Open = 1.22M,High = 1.24M,Low = 1.21M,Close = 1.23M,Average = 1.225M,
Time = new DateTime(2012, 11, 9, 12, 23, 23, 222)},
new XRowModified(){ Id = 1551, Open = 1.20M,High = 1.24M,Low = 1.22M,Close = 1.20M,Average = 1.23M,
Time = new DateTime(2012, 11, 9, 12, 23, 25, 122)}}},
new ZRowCollection(){P = 1,High = 3,Low = 0, XRowModified = new List<XRowModified>(){
new XRowModified(){ Id = 1555, Open = 1.22M,High = 1.24M,Low = 1.21M,Close = 1.23M,Average = 1.225M,
Time = new DateTime(2012, 11, 9, 12, 23, 40, 422)},
new XRowModified(){ Id = 1556, Open = 1.20M,High = 1.25M,Low = 1.20M,Close = 1.20M,Average = 1.23M,
Time = new DateTime(2012, 11, 9, 12, 23, 46, 522)}}},
new ZRowCollection(){P = 2,High = 2,Low = 0, XRowModified = new List<XRowModified>(){
new XRowModified(){ Id = 1558, Open = 1.22M,High = 1.24M,Low = 1.21M,Close = 1.23M,Average = 1.225M,
Time = new DateTime(2012, 11, 9, 12, 30, 11, 622)},
new XRowModified(){ Id = 1559, Open = 1.20M,High = 1.24M,Low = 1.22M,Close = 1.20M,Average = 1.23M,
Time = new DateTime(2012, 11, 9, 12, 30, 12, 822)}}}
};
List<ZRowCollection> zListOutput = new List<ZRowCollection>(){
new ZRowCollection(){P = 0,High = 4,Low = 0, XRowModified = new List<XRowModified>(){
new XRowModified(){ Id = 1550, Open = 1.22M,High = 1.24M,Low = 1.21M,Close = 1.23M,Average = 1.225M,
Time = new DateTime(2012, 11, 9, 12, 23, 23, 222)},
new XRowModified(){ Id = 1551, Open = 1.20M,High = 1.24M,Low = 1.22M,Close = 1.20M,Average = 1.23M,
Time = new DateTime(2012, 11, 9, 12, 23, 25, 122)}}}
};
In this case I would consider writing a custom equality comparer, which could then be plugged in to the Distinct method. To do this you need two functions Equals and GetHashCode.
Note: It is important the GetHashCode returns the same hash for two equal objects as this is the first thing that Distinct checks.
From what I gather from your code two ZRow's are equal if their XRow's have the same sequence of averages, so our equality is that averageSequence1.SequenceEqual(averageSequence2) which would be implemented as so:
public class CustomComparer : IEqualityComparer<ZRowCollection>
{
public static CustomComparer Instance { get { return new CustomComparer(); } }
Int32 IEqualityComparer<ZRowCollection>.GetHashCode(ZRowCollection value)
{
//One could also use the sum of the averages here, but went for simplicity...
return value.XRowModified.Count;
}
Boolean IEqualityComparer<ZRowCollection>.Equals(ZRowCollection z1, ZRowCollection z2)
{
return z1.XRowModified.Select(x => x.Average)
.SequenceEqual(z2.XRowModified.Select(x => x.Average));
}
}
and which would be used like so:
var distinctList = zListCollection.Distinct(CustomComparer.Instance);