r3plica
r3plica

Reputation: 13367

c# linq to select items with same field value except the first

So, I have this list of products in JSON:

var products = JArray.Parse(@"[{
    id: 1,
    name: 'Product 1',
    variantId: 1
}, {
    id: 2,
    name: 'Product 2',
    variantId: 1
}, {
    id: 3,
    name: 'Product 3',
    variantId: 1
}, {
    id: 4,
    name: 'Product 4',
    variantId: 4
}, {
    id: 5,
    name: 'Product 5',
    variantId: 4
}]");

And it is read into my API as a list of JObject. Currently I do this:

var sortedProducts = _sortProvider.SortByDrive(products, questions);
var productsToRemove = new List<JObject>();
var variant = "________NOTHING________";
for (var i = sortedProducts.Count - 1; i >= 0; i--)
{
    var product = sortedProducts[i];
    var productVariant = product.SelectToken("variant").ToString();
    if (productVariant.Equals(variant))
        productsToRemove.Add(product);
    variant = productVariant;
}
products.RemoveAll(x => productsToRemove.Contains(x));

But I I want to use Linq to get the products (to remove). For the code above you should see that basically I want it to get all products that have the same variantId but skip the first one. So in the example above, it should return this:

var products = JArray.Parse(@"[{
    id: 2,
    name: 'Product 2',
    variantId: 1
}, {
    id: 3,
    name: 'Product 3',
    variantId: 1
}, {
    id: 5,
    name: 'Product 5',
    variantId: 4
}]");

I hope that makes sense.

Upvotes: 0

Views: 267

Answers (2)

Flater
Flater

Reputation: 13773

The other answer, while it will usually work, is not guaranteed to work. It assumes that the first item in a group is always the "master" item.

But this will break if the parent is not the first item in its group, e.g.:

var products = JArray.Parse(@"[{
    id: 2,
    name: 'Product 2',     //SWAPPED
    variantId: 1
}, {
    id: 1,
    name: 'Product 1',     //SWAPPED
    variantId: 1
}, {
    id: 3,
    name: 'Product 3',
    variantId: 1
}, {
    id: 4,
    name: 'Product 4',
    variantId: 4
}, {
    id: 5,
    name: 'Product 5',
    variantId: 4
}]");

To be fair to @Stop-Cran, you did explicitly ask to exclude the "first" item. He answered the question as it was asked, but I doubt that's the actual problem you're trying to solve.


It seems like you want to exclude the "master" variant of a product line, i.e. the products who have themselves set as their variantId.

Going by those criteria, a more guaranteed approach would be to use that trait (obj.Id == obj.variantId) to exclude them:

new JArray(sortedProducts.Where(p => p.id != p.variantId));

Upvotes: 0

stop-cran
stop-cran

Reputation: 4408

Group by variantId and select all items except first from each of the groups (and enclose with JArray if you need to return JSON):

new JArray(sortedProducts.GroupBy(p => p["variantId"]).SelectMany(g => g.Skip(1)));

This yields for me:

[{
  "id": 2,
  "name": "Product 2",
  "variantId": 1
},
{
  "id": 3,
  "name": "Product 3",
  "variantId": 1
},
{
  "id": 5,
  "name": "Product 5",
  "variantId": 4
}]

Upvotes: 3

Related Questions