6

I have a class Items with properties ( Name, Price).

   Item1       $100
   Item2       $200
   Item3       $150
   Item1       $500
   Item3       $150

I want to remove items only if Name exists more than once and price is $500 using LINQ and without creating Custom comparer? for above one item1 with $500 will be removed from list.

Thanks,

user570715
  • 639
  • 3
  • 12
  • 28

7 Answers7

8

Try this:

var result = items
    .GroupBy(item => item.Name)
    .SelectMany(g => g.Count() > 1 ? g.Where(x => x.Price != 500) : g);

First group by name. If the group has more than 1 item, select only items from the group where the price is not 500.

david.s
  • 11,283
  • 6
  • 50
  • 82
4
var result =
    from item in items
    where item.Price != 500 || items.Count(i => i.Name == item.Name) == 1
    select item;
Helstein
  • 330
  • 2
  • 6
4

I would first create a pre-evaluated subset list containing duplicates:

var dupes = list.Where(a => list.Count(b => b.Name.Equals(a.Name)) > 1).ToList();

.ToList() ensures this query is only evaluated once. This will make a huge difference in speed if the list is large.

Now if your list is a List<>, you can use the RemoveAll() method:

list.RemoveAll(item => item.Price == 500 && dupes.Contains(item));

And you're done.

But if your list is only known to be IEnumerable<>, or you don't want to modify the source list, or you want deferred execution, then just use LINQ:

var result = list.Where(item => !(item.Price == 500 && dupes.Contains(item)));

This will be evaluated when you enumerate result.

Igby Largeman
  • 16,495
  • 3
  • 60
  • 86
2

Finding duplicated items can be done by:

var dups = lst.Where(x=>lst.Any(y => y != x && y.Name == x.Name))

Finding duplicated item with price 500 can be done by:

var dups500 = dups.Where(x=>x.Price == 500);

Finally removing dups500 can be done by using except method:

var result = lst.Except(dup);

Or all in one :

var result = 
     lst.Except(
               lst
               .Where(x=>x.Price == 500 && 
                         lst.Any(y => y != x && y.Name == x.Name))).ToList();
Saeed Amiri
  • 22,252
  • 5
  • 45
  • 83
  • @KirkWoll, thats depend to your taste, but it's not confusing: `Except` means `Except`, and inner `where` searches for items with given criteria, seems simple :) but that depends to your choice. (also this is faster than groupby one). – Saeed Amiri May 21 '12 at 21:45
  • 1
    This does not keep both Item3s – Marty Neal May 21 '12 at 21:46
  • @MartinNeal, I couldn't understand what you mean? – Saeed Amiri May 21 '12 at 21:51
  • 1
    @Saeed: `Except` returns the "set difference" of the two sequences (ie, it excludes duplicates). Since there are two items in the OP's example with `{Name="Item3",Price=$150}` then it's possible that one of those items will be excluded by `Except` (for example, if they're the same object; or if they have an `Equals` method that treats them as equal; or if you're using an `IEqualityComparer<>` that treats them as equal). But if they're not considered to be equal and they're just two objects that happen to share the same name and price then you'll be ok. – LukeH May 21 '12 at 22:04
  • Hmmm, it depends on what the OP has for his Item class. I was testing with an anonymous class and the y!=x portion behaves differently. – Marty Neal May 21 '12 at 22:10
  • @LukeH, Instead of except I could use `!`, but I used except to make it more readable, so changes are not hard, also when OP don't like to use `IEqualityComparer` means just equal method works here, and by watching OPs requirements seems he didn't override equal method such that just working on Name. – Saeed Amiri May 22 '12 at 07:20
1
var result = from np in NamePriceCollection
where NamePriceCollection.Count(x => x.Name == np.Name) > 1 && np.Price == 500
select np;

// you have the list of items for the specified condition here. Remove them from underlying collection

Soundararajan
  • 2,000
  • 21
  • 23
0

I want to remove items only if Name exists more than once and price is $500

Apple 300 <-- winner
Apple 500 <-- dupe
Banana 500  <-- winner
Banana 500  <-- dupe
Banana 500  <-- dupe
Cantelope 100 <-- winner
Cantelope 200 <-- winner

The second Apple is a dupe, obviously. Banana has three items with price == 500. One is a winner. The rest are dupes. There are no price == 500 Cantelopes, so there are no dupes, just winners.

from item in source
group item by item.Name into g
let okItems = g.Where(x => x.Price != 500)
let secondChoiceItem = g.FirstOrDefault(x => x.Price == 500)
let theItems = okItems.DefaultIfEmpty(secondChoiceItem)
from nonDupeItem in theItems
select nonDupeItem
Amy B
  • 108,202
  • 21
  • 135
  • 185
-2
var Test = (from row in DataTable.AsEnumerable()
            select row.Field<string>("ColumnName")).Distinct();
Servy
  • 202,030
  • 26
  • 332
  • 449
shiju87
  • 112
  • 2
  • 11