Selecting objects from two lists of objects [duplicate] - c#

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();

Related

Checking whether a property value equals to a predefined one in a list of objects

I have two classes like this
public class Stock
{
public StockItem Item;
public string Location;
public int Quantity;
public string Price;
}
public class StockItem
{
public string Code;
public string Name;
public string Unit;
}
And I have a list that contains multiple instances of the Stock class
var stockList = new List<Stock>();
I am trying to determine whether the Name property of each instance inside the list is equal to a predefined string. Currently, I am looping through the list like this
foreach (var stock in stockList)
{
if (stock.Item.Name.ToLower() == "test")
{
Console.WriteLine("Found the class")
break;
}
}
However, I was wondering if there was a more efficient way to do this using Linq or something similar to the .Contains method. Is there a simpler or more efficient way to accomplish this?
whether the Name property of each instance inside the list is equal
to a predefined string
Not much more efficient but simpler:
bool allAreEqual = stockList.All(x => x.Item.Name.Equals("test", StringComparison.OrdinalIgnoreCase))
If you instead want to find the first which matches the condition(what your loop really does):
Stock si = stockList.FirstOrDefault(x => x.Item.Name.Equals("test", StringComparison.OrdinalIgnoreCase));
Now you know if such a Stock exists(si != null) at all and you got it.
All in linq will return True or false
stockList.All(p => p.Item.Name.ToLower() == "test");
You can use the Linq Any() method:
bool containsItemName = stockList.Any(x => x.Item.Name.Equals("MyName", StringComparison.InvariantCultureIgnoreCase));
Are you really looking at all instances? From your question, it seems as if Anymight be the way to go, see here.
stockList.Any(p => p.Item.Name.ToLower() == "test");
You can get a result what you wanted by calling Any
bool result = stockList.Any(
stock => stock.Item.Name.Equals("text", StringComparison.InvariantCultureIgnoreCase)
);
In this code, the parameter name stock can be changed whatever you want.

How to return Linq expression as a List? [duplicate]

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

Combining parts of one list into another List LINQ [duplicate]

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();

how can I create a list of lists if I have a list of objects in c# [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I have an object that looks like this
public class CompletionRow
{
public int Pass;
public int Fail;
public int Blocked;
public int NA;
public string DesignName;
public double WorkWeek;
public int CompletionStatus;
}
I want to create a list that contains another list with two of these values. For example, I want a list like this:
Edit
public class Vals
{
string DesignName;
int CompletionStatus;
}
List<List<Vals>> eachCustomer = new List<List<Vals>>();
If I have a my list of object like this:
List<CompletionRow> results = new List<CompletionRow>();
is it possible to get this into my double list? I've tried to do something with linq where I select a value and then use .ToList() but I couldn't figure out how to do this with an extra list inside.
Generally you'd just use either a Tuple<string, int>, anonymous type, KeyValuePair<string, int>, or a concrete type that you define. It just depends on the context. Although if youre passing it out to another type, I'd create another class.
Then you can, as you suggested, use LINQ.
return results.Select(c => new { DesignName = c.DesignName, CompletionStatus = c.CompletionStatus }).ToList();
This is the anonymous type solution, but I'd be wary of that approach unless you're using it only in the scope of the defining function. Otherwise, use Tuple or a concrete type. Preferably the latter, of course.
You can't have a list that contains multiple items. That's just not what lists are. Unless you're looking for a dictionary:
return results.ToDictionary(c => c.DesignName, c => c.CompletionStatus);
That will create a dictionary (which if you append .ToList() will become a List<KeyValuePair<string, int>>), where DesignName is the key and CompletionStatus is the value.
Edit:
Although looking at your particular phrase "which contains an inner list that has two properties from my object (the DesignName and the CoompletionStatus)," I'm a little confused. If you actually do want a List<List<T>> as your title suggests, the greatest common denominator between the type of DesignName and CompletionStatus is object. So this will be terrible to work with.
return results.Select(c => new List<object>() { c.DesignName, c.CompletionStatus }).ToList();
If you did, for whatever reason, actually decide you wanted that, I would at least leave it as a List<object[]>. But I can't imagine a single scenario where this would actually be useful.
Edit 2:
With the introduction of your Vals type to the original question, I don't really see how you'd make a List<List<Vals>> but a List<Vals> is easy and appropriate:
return results.Select(c => new Vals() { DesignName = c.DesignName, CompletionStatus = c.CompletionStatus }).ToList();
You can use linq to create a new list if you want:
var newlist = results
.Select(x => new { Name : x.DesignName,
Status : x.CompletionStatus }).ToList();
"DesignName" property of CompletionRow class can be replaced with a list of Vals object:
public class CompletionRow
{
public int Pass;
public int Fail;
public int Blocked;
public int NA;
public List<Vals> DesignList { get; set; }
public double WorkWeek;
}
This way, List< CompletionRow > results can hold list of Vals in it.

Single LINQ Query on 3 separate collections

I have an object that has 3 separate Dictionaries. The value parameter for each dictionary implements the same interface. What is the best method to combine the 3 dictionaries into one and perform a single query so the results from the query will be a single IEnumerable?
Here's a rough idea of I am trying to accomplish. My DataSet object contains 3 dictionaries, each of which should be very small (theoretically some could contain up to 100 elements, but except in the most extreme cases they will be always less than 20 and usually 6 or less).
The purpose of the GetAllId() method will be to retrieve the Id for several private fields in each element of each dictionary and return it as a single IEnumerable. The dictionary value objects all implement IIdQueryable, which defines a single method that will extract all of the required Id's in the object.
I have 2 different ideas on how to accomplish what I want, but I am not sure if there is a better way to accomplish this?
public class DataSet
{
Dictionary<Int32, Foo> dict1;
Dictionary<CustomKey, Bar> dict2;
Dictionary<Int32, Boo> dict3;
public IEnumerable<Int32> GetAllId
{
// need to retrieve Id from dict1, dict2, and dict3.
// implementation ideas below
}
}
Option 1
public IEnumerable<Int32> GetAllId
{
var q1 = dict.Values.SelectMany(g => g.GetId());
var q2 = dict.Values.SelectMany(g => g.GetId());
var q3 = dict.Values.SelectMany(g => g.GetId());
return q1.Concat(q2).Concat(q3);
}
Option 2
public IEnumerable<Int32> GetAllId
{
var c1 = dict1.Values.Cast<IIdQueryable>();
var c2 = dict2.Values.Cast<IIdQueryable>();
var c3 = dict2.Values.Cast<IIdQueryable>();
var collection = c1.Concat(c2).Concat(c3);
return collection.SelectMany(g => g.GetId());
}
Method #3
Since each object implements the same interface, is it possible to perform a single LINQ query on all 3 objects without casting?
I personally like Method #1 better as it doesn't involve casting anything, but I think Method #2 seems to be more readable.
If it is needed, here's a rough idea of how the interface is implemented
public interface IIdQueryable
{
IEnumerable<Int32> GetId();
}
public class Foo : IIdQueryable
{
public IEnumerable<Int32> GetId()
{
//returns Id of all elements in this object
}
}
public class Bar : IGuidQueryable
{
public IEnumerable<Int32> GetId()
{
//returns Id of all elements in this object
}
}
public class Boo : IGuidQueryable
{
public IEnumerable<Int32> GetId()
{
//returns Id of all elements in this object
}
}
EDIT:
The question title is the source of what I was hoping could be done (that is do all 3 lookups in a single query without casting). I clarified that above.
You just need one SelectMany call in the first approach:
public IEnumerable<Int32> GetAllId()
{
return dict1.Values
.Select(x => x.GetId())
.Concat(dict2.Values.Select( x=> x.GetId()))
.Concat(dict3.Values.Select(x => x.GetId()))
.SelectMany(x => x);
}
Personally I wouldn't duct-tape this together though, there is no performance impact by keeping the queries separate and just returning the concatenation like you did already in the first example - it is more readable to me:
public IEnumerable<Int32> GetAllId()
{
var q1 = dict1.Values.Select(g => g.GetId());
var q2 = dict2.Values.Select(g => g.GetId());
var q3 = dict3.Values.Select(g => g.GetId());
return q1.Concat(q2)
.Concat(q3)
.SelectMany(x => x);
}
Now this looks pretty close to the second approach already - but no cast needed.

Categories