Distinct on multiple fields - c#

I Have a List of some Properties as Model
public class AnswerList {
public int ID { get; set; }
public int? Schedule_ID { get; set; }
public int? SubItemID { get; set; }
public string SubItemName { get; set; }
public string ItemName { get; set; }
public string Answer { get; set; }
public string Remarks { get; set; }
public string Remarks_Flag { get; set; }
public string Lattitude { get; set; }
public string Longitude { get; set; }
public DateTime? Load_Date { get; set; }
}
I was getting list of Distinct Sub Items from this List
List<string> sub_item_list = AnswerList.Select(x => x.SubItemName).Distinct().ToList();
Now I want data in different format as per below class
public class SubItemList {
public string ItemName { get; set; }
public string SubItemName { get; set; }
}
My requirement is to get distinct sub item with their respective Item Names , Sub Item should be distinct but Item Name can be repeated as one Item can contain multiple Subitem
Distinct Does not work on multiple values so I tried
List<SubItemList> SI_List =
AnswerList.GroupBy(d => d.SubItemID)
.Select(x =>
new SubItemList
{
ItemName = x.Select(a => a.ItemName).First(),
SubItemName = x.Select(a => a.SubItemName).First()
}).Distinct().ToList();
This way I am getting what I want but I don't think its a preferable approach ,
Linq expression inside another Linq expression
How can I get it with a simple Linq expression ?
I am using ASP.Net Core 2.0

If the expectation is what you have asked in the question, then following shall be the query:
AnswerList.GroupBy(d => new { d.SubItemID, d.ItemName, d.SubItemName})
.Select(x => new SubItemList{
ItemName = x.Key.ItemName,
SubItemName =x.Key.SubItemName
}
).Distinct();
How it works
GroupBy unique combination of SubItemID, ItemName, SubItemName, which will form the grouping key
Now only Pick the ItemName, SubItemName to create SubItemList and call Distinct to remove duplicates even across SubItemID
For Distinct to work correctly for the class SubItemList either implement IEquatable<SubItemList> or supply the IEqualityComparer<SubItemList> to the Distinct

Try with
GroupBy(
p => new {p.ItemName, p.SubItemName}
).Select(g => new { g.Key.ItemName, g.Key.SubItemName });

Related

How to filter out items that are in a list of a list?

I am a little puzzled to how I can add items depending on the value that is in a list of a list.
I have these models
public class ItemsModel
{
public int OrderItemId { get; set; }
public string Sku { get; set; }
public string Name { get; set; }
public int Quantity { get; set; }
}
public class OrdersModel
{
public int OrderId { get; set; }
public string OrderNumber { get; set; }
public List<ItemsModel> Items { get; set; }
}
public class OrderResultModel
{
public List<OrdersModel> Orders { get; set; }
}
Question
I need to add all orders from an api, but add Items that has SKU only ending with "5".
How can I do this?
How I tried it
I have an API call to get all orders.. List<OrdersModel> GetOrders().
Then I add the data like so:
public ObservableCollection<OrdersModel> Orders { get; private set; }
...
Orders = new ObservableCollection<OrdersModel>();
foreach (var item in GetOrders())
{
Orders.Add(item);
}
Here is how I tried to add values with SKU ending with 5:
var list = GetOrders().Where(x => x.Items.Any(i => i.Sku.EndsWith("5")));
foreach (var item in list)
{
Orders.Add(item);
}
Problem
This still shows me all values.. why? And how I can correct it?
foreach(var order in GetOrders())
{
order.Items = order.Items.Where(i => i.Sku.EndsWith("5")).ToList();
Orders.Add(order);
}
It's showing you all the value because Any() will evaluate to true if any of List of ItemsModels ends with 5.
you should filter on the list first something like
var filteredItems = orders.Items.Where(i => i.sku.EndsWith("5"))

Comparing Arrays LINQ

How can I compare to array in linq and get all elements where there is at least one intersection?
Example:
selectes = {1,5,7}
Bands[0].SongsID {1,9}
Bands[1].SongsID {5,6}
Bands[2].SongsID {4,6}
I need to select Bands[0] and Bands[1].
I tried this:
var selectes2 = Bands.Where(t => t.SongsID.Intersect(selectes));
Bands class:
public class Band
{
public int ID { get; set; }
public string Name { get; set; }
public DateTime YearOfCreate { get; set; }
public string Country { get; set; }
public int[] SongsID { get; set; }
}
var selectes2 = Bands.Where(t => t.SongsID.Intersect(selectes).Any());
Assuming you mean to select any band that has any song ID that matches your list of ids, you could accomplish that with this:
var matchingBands = Bands.Where(band => band.SongsID.Any(selectes.Contains));

Multiple collections in an object using Linq

I have following object
public class bizObj
{
public string name { get; set; }
public int p_id { get; set; }
public string acc_number { get; set; }
public string a_name { get; set; }
public string a_phone { get; set; }
public virtual product product { get; set; }
public virtual account account { get; set; }
}
Linq statment to get data from db is
public IEnumerable<bizObj> GetbizObj(int id)
{
var acs = (from c in db.p_account
where c.p_id==id
select new bizObj
{
name = c.p_name,
p_id = c.product.id,
acc_number=c.account.acc_number,
a_name = c.a_name,
a_phone = c.a_phone
});
return acs;
}
The above code is working fine but it is returning one collection. What I am trying to
get is that it has a collection of
{
name,
p_id
//than a second collection which has all the records that have same name ane p_id
{
acc_number,
a_name
a_phone
}
}
Please let me know how I can accomplish this using linq/lambda expression. Thanks
Question is unclear, but it looks like you're saying you want to group rows by name and p_id.
var query = acs.GroupBy(x => new { x.name, x.p_id })
.Select(g => new { g.Key.name, g.Key.p_id, Items = g.ToList() });

Linq select nested rows

I have the following class:
public class PingtreeTier
{
public BuyerType BuyerType { get; set; }
public int ID { get; set; }
public int MaxRequests { get; set; }
public IEnumerable<PingtreeNode> Nodes { get; set; }
public int Seq { get; set; }
public int Timeout { get; set; }
public bool Weighted { get; set; }
}
As you can see PingtreeTier contains an IEnumerable<PingtreeNode> class. This PingtreeNode class has a property named Status. Using Linq, I need to select only the Tiers/Nodes where PingtreeNode Status = 'Active'.
Anyone help as I'm struggling with the syntax for this.
How about using .Any or .All here:
var results = tiers.Where(t => t.Nodes.Any(n => n.Status == "Active"));
This will select any PingtreeTiers that contain at least one PingTreeNode with Status equal to "Active".
If you wanted to select only PingtreeTiers whose PingTreeNodes are all active, you could use the .All extension method instead:
var results = tiers.Where(t => t.Nodes.All(n => n.Status == "Active"));

Use IN operator in LINQ

I have List<Candidate> Candidates, List<Seat> Seats
The Model defined as shown below
public class Seat
{
public string CollegeId { get; set; }
public bool isFilled { get; set; }
public string SeatType { get; set; }
public string RollNumber { get; set; }
}
public class Candidate
{
public string RollNumber { get; set; }
public bool isAllotted { get; set; }
public string Quota { get; set; }
public int CandidateRank { get; set; }
public List<OptionPriority> SeatingPriorities { get; set; }
}
public class OptionPriority
{
public string CollegeId { get; set; }
public int PriorityRank { get; set; }
}
I need to filter List<Seat> from List<Seat> Seats where Seats.CollegeId IN List of CollegeID in SeatingPriorities.
// same as EXISTS
Seats.Where(s => SeatingPriorities.Any(sp => sp.CollegeId == s.CollegeId))
Also you can join seatings with seatings priorities:
// same as INNER JOIN
var prioritySeats = from s in Seats
join sp in SeatingPriorities
on s.CollegeId equals sp.CollegeId
select s;
NOTE: Both of queries above will not generate IN clause if you will execute them in LINQ to SQL or LINQ to Entities. IN is generated when you use Contains method of primitive types list:
var ids = SeatingPriorities.Select(sp => sp.CollegeId).ToList();
// same as IN
var prioritySeats = Seats.Where(s => ids.Contains(s.CollegeId));
var results = source.Where(x => SeatingPriorities.Contains(x.CollegeId)).ToList();
You can use Enumerable.Contains to find out the matches like you do with in
var result = lstSeats.Where(s=>SeatingPriorities.Contains(s.CollegeId));
Use Contains to achieve IN functionality in LINQ
You could use Any:
seats.Where(s => SeatingPriorities.Any(i => i.Id == s.CollegeId))
Since Contains only accepts an instance to compare (along with a possible IEqualityComparer<T>), which won't work if OptionPriority isn't an comparable to CollegeId (i.e. a string).

Categories

Resources