tags:

views:

137

answers:

3

I have a class called Item. Item has an identifier property called ItemCode which is a string. I would like to get a list of all non-distinct Items in a list of Items.

Example:

List<Item> itemList = new List<Item>()
{
   new Item("code1", "description1"),
   new Item("code2", "description2"),
   new Item("code2", "description3"),
};

I want a list containing the bottom two entries

If I use

var distinctItems = itemsList.Distinct();

I get the list of distinct items which is great, but I want almost the opposite of that. I could subtract the the distinct list from the original list but that wouldn't contain ALL repeats, just one instance of each.

I've had a play and can't figure out an elegant solution. Any pointers or help would be much appreciated. Thanks!

I have 3.5 so LINQ is available

+2  A: 

You might want to try it with group by operator. The idea would be to group them by the ItemCode and taking the groups with more than one member, something like :

var grouped = from i in itemList
              group i by i.ItemCode into g
              select new { Code = g.Key, Items = g };

var result = from g in grouped 
             where g.Items.Count() > 1;
Thomas Wanner
I can't get this to compile. It moans about the 'group by' and the 'into' statements
RichK
I've forgotten the "i" between group and by :$ Now it's fixed, but it's essentially the same thing as magnus wrote.
Thomas Wanner
+1  A: 

My take:

var distinctItems = 
    from list in itemsList
    group list by list.ItemCode into grouped
    where grouped.Count() > 1
    select grouped;
magnus
Thanks magnus (and Thomas) and I wouldn't have thought to use GroupBy
RichK
A: 

I'd suggest writing a custom extension method, something like this:

static class RepeatedExtension
{
    public static IEnumerable<T> Repeated<T>(this IEnumerable<T> source)
    {
        var distinct = new Dictionary<T, int>();
        foreach (var item in source)
        {
            if (!distinct.ContainsKey(item))
                distinct.Add(item, 1);
            else
            {
                if (distinct[item]++ == 1) // only yield items on first repeated occurence
                    yield return item;
            }                    
        }
    }
}

You also need to override Equals() method for your Item class, so that items are correctly compared by their code.

Chriso