This question already has answers here:
Distinct not working with LINQ to Objects [duplicate]
(11 answers)
Closed 7 years ago.
I am trying to figure out how to select distinct values from one list and then transpose those distinct values to another list.
I have this:
Model:
public class Participant
{
public int UserId { get; set; }
public string Name { get; set; }
}
Controller Code:
List<Participant> participants = new List<Participant>();
participants = project
.QuickView
.Select(x => new Participant { x.UserId, x.FullName})
.Distinct()
.ToList();
That seems to get me the distinct values UserId and FullName but not in the List format I need. I get an IEnumerable format not List format. What am I missing to get the LINQ to place the the results in a new Participant List?
You dont really want to be using the select. Instead use a custom IEqualityComparer with the Distinct method. Something like this
public class CustomEqualityComparer : IEqualityComparer<Participant>
{
public bool Equals(Participant x, Participant y)
{
return x.UserId == y.UserId && x.Name == y.Name;
}
public int GetHashCode(Participant obj)
{
return new Tuple<int, string>(obj.UserId, obj.Name).GetHashCode();
}
}
Then your call would look like this:
participants = project.QuickView.Distinct(new CustomEqualityComparer()).ToList();
Related
This question already has answers here:
Flatten an Array in C# [duplicate]
(2 answers)
Closed 2 years ago.
I have a list inside a list, I need to convert it to list of string.
Below are the list properties.
List<UserOrganization> UserOrganizations { get; set; }
public interface UserOrganization
{
IEnumerable<UserRole> Roles { get; set; }
}
public class UserRole
{
public int RoleId { get; set; }
}
I need to find all RoleId and return them in a list of string.
I tried below code but unable to get a list of string from it.
var securityRoleIds= CallingUser.UserOrganizations.Select(x => x.Roles.Select(y=> y.RoleId).ToList()).ToList();
List<string> l2 = securityRoleIds.ConvertAll<string>(delegate(Int32 i) { return i.ToString(); });
Getting this error.
Cannot convert anonymous method to type 'Converter, string>'
because the parameter types do not match the delegate parameter types
Use SelectMany rather than Select:
List<string> list = CallingUser.UserOrganizations
.SelectMany(x => x.Roles.Select(y => y.RoleId.ToString()))
.ToList();
SelectMany flattens the nested collections.
Also, you can just use ToString() on each int in the collection, rather than converting them later.
This question already has answers here:
Linq to EntityFramework DateTime
(4 answers)
Closed 2 years ago.
I have a method that looks like this
public class Site
{
public virtual ICollection<SalesOrder> soDetails { get; private set; }
public int? IncomingOSI(Site s)
{
PIC_Program_1_0Context db = new PIC_Program_1_0Context();
List<SalesOrder> so = db.SalesOrders
.Where(x => x.siteID == s.ID)
.Where(x => x.DateCreated > DateTime.Now.AddDays(-30)).ToList();
}
}
But currently this returns an error of
'LINQ to Entities does not recognize the method 'System.DateTime AddDays(Double)' method, and this method cannot be translated into a store expression.'
What is the reason for this?
Declare it as a variable outside of the linq expression.
public class Site
{
public virtual ICollection<SalesOrder> soDetails { get; private set; }
public int? IncomingOSI(Site s)
{
PIC_Program_1_0Context db = new PIC_Program_1_0Context();
// declare it outside of the expression
var less30days = DateTime.Now.AddDays(-30);
List<SalesOrder> so = db.SalesOrders.Where(x => x.siteID == s.ID).Where(x => x.DateCreated > less30days).ToList();
}
}
The answer here explains why; Linq won't be able to run other C# code as it will have issues turning it to a sql expression.
LINQ to Entities does not recognize the method
This question already has an answer here:
Return Linq query results into List object
(1 answer)
Closed 6 years ago.
How to return below code into List
public List<tbl_Employee> getProgramNames()
{
IQueryable<tbl_CentralLookup> data = db.tbl_Employee.Where(c => c.EmpName == "sam").Select(o => new { o.LookupId, o.EmpName });
return data;
}
Your method's return type is List of tbl_Employee. So make sure your LINQ expression is also returning the same type data.
public List<tbl_Employee> getProgramNames()
{
return db.tbl_Employee.Where(c => c.EmpName == "sam").ToList();
}
Assuming db.tbl_Employee of DbSet<tbl_Employee> type.
Also i suggest you follow PascalCasing for C# methods. So i would rename getProgramNames to GetProgramNames :)
EDIT : As per the question in comment
How to specify a column names. I want to retrieve data only for two
columns.
If you want only 2 columns, create a DTO for that data structure and use that for projecting the data in your LINQ expression.
public class EmployeeBasicInfo
{
public int Id { set;get;}
public string FirstName { set;get;}
}
Now change your method to return a collection of this DTO instead of the entity.
public List<EmployeeBasicInfo> getProgramNames()
{
return db.tbl_Employee.Where(c => c.EmpName == "sam")
.Select(x=> new EmployeeBasicInfo { Id=x.Id, FirstName = x.EmpName })
.ToList();
}
Assuming your tbl_Employee entity class has an Id property of type Int
I'm trying to convert a list of objects to a dictionary using the following code:
var MyDictionary = MyList.Distinct().ToDictionary(i => i.ObjectId, i => i);
I know that a dictionary should not contain duplicate elements, hence the .Distinct(). Yet I still get the following Exception whenever there's a duplicate element:
An item with the same key has already been added.
MyList is a list of MyObject that looks like this:
public class MyObject{
public string ObjectId { get; set; }
public string FName { get; set; }
public string LName { get; set; }
}
Is there a better way to create a dictionary from a list of objects ? or am I doing something wrong?
If you want to compare on the ObjectId, you'll need to pass in a custom comparer to .Distinct(). You can do so like this:
class MyObjectComparer : IEqualityComparer<MyObject>
{
public bool Equals(MyObject x, MyObject y)
{
return x.ObjectId == y.ObjectId;
}
public int GetHashCode(MyObject obj)
{
return obj.ObjectId.GetHashCode();
}
}
var MyDictionary = MyList
.Distinct(new MyObjectComparer())
.ToDictionary(i => i.ObjectId, i => i);
You could use Group by and then select first from the List as below:
var MyDictionary = MyList.GroupBy(i => i.ObjectId, i => i).ToDictionary(i => i.Key, i => i.First());
Distinct works using the objects built in Equals and GetHashCode methods by default but your dictionary works only over the id. You need to pass in a IEqualityComparer in to distinct that does the comparison on Id to test if items are equal or make MyObject implment Equals and GetHashCode and have that compare on the Id.
This question already has answers here:
Linq Except considering only one property
(2 answers)
Closed 6 years ago.
I have a method that takes two lists as arguments and returns a list with the objects shared by the two arguments by comparing their name. It looks like this:
static List<Department> InCommon(List<Department> list_a, List<Department> list_b)
{
List<Department> a_list = new List<Department>();
var names = list_b.Select(item => item.Name);
a_list = list_a.Where(item => names.Contains(item.Name)).ToList();
return a_list;
}
I need a second method that does something similar. It should be able to return the objects in list_a after having removed the objects in list_b from it. list_a minus list_b, so to speak. I suspect
List<T>.Except
might be the solution, but how can I achieve this?
To use Except you would need to implement an IEqualityComparer<Department> that compares two Department instances by their Name properties.
So an easier way may be this:
return list_a.Where(a => list_b.All(b => a.Name != b.Name)).ToList();
This takes all elements from list_a with a Name that does not occure in list_b.
For the Except version you would need an IEqualityComparer<Department> like this:
public class DepartmentByNameComparer : IEqualityComparer<Department>
{
public bool Equals(Department x, Department y)
{
return x.Name == y.Name;
}
public int GetHashCode(Department obj)
{
return obj.Name.GetHashCode();
}
}
Then you could call Except like this:
return list_a.Except(list_b, new DepartmentByNameComparer()).ToList();