canceo
canceo

Reputation: 49

Get only unique elements from a list

Have a list with deviceIds and corresponding actions to be taken on device.

var results= new List<Result>
{
    new Result{ DeviceId= 1, ActionType = 1 },
    new Result{ DeviceId= 1, ActionType = 2 },
    new Result{ DeviceId= 1, ActionType = 3 },
    new Result{ DeviceId= 2, ActionType = 1 },
    new Result{ DeviceId= 3, ActionType = 1 },
    new Result{ DeviceId= 4, ActionType = 1 },
    new Result{ DeviceId= 5, ActionType = 1 },
    new Result{ DeviceId= 6, ActionType = 1 },
    new Result{ DeviceId= 6, ActionType = 2 },

};

How do I filter deviceIds unique in the list(no DeviceId 1), and assign it back to var "results"

results = List<Result>
{
    new Result{ DeviceId= 2, ActionType = 1 },
    new Result{ DeviceId= 3, ActionType = 1 },
    new Result{ DeviceId= 4, ActionType = 1 },
    new Result{ DeviceId= 5, ActionType = 1 },
};

Have tried using groupby and couldn't move forward

   results =  from result in results
              group result by result.DeviceId
              into groupedResultsByDevice
              where groupedResultsByDevice.Count() == 1
              select ????

Upvotes: 0

Views: 119

Answers (4)

GSerjo
GSerjo

Reputation: 4778

Check this out

    public static void Main()
    {
        var results = new List<Result>
                          {
                              new Result {DeviceId = 1, ActionType = 1},
                              new Result {DeviceId = 1, ActionType = 2},
                              new Result {DeviceId = 1, ActionType = 3},
                              new Result {DeviceId = 2, ActionType = 1},
                              new Result {DeviceId = 3, ActionType = 1},
                              new Result {DeviceId = 4, ActionType = 1},
                              new Result {DeviceId = 5, ActionType = 1},
                              new Result {DeviceId = 6, ActionType = 1},
                              new Result {DeviceId = 6, ActionType = 2},
                          };
        List<Result> result = results
            .GroupBy(x => x.DeviceId)
            .Where(x => x.Count() == 1)
            .SelectMany(x => x)
            .Distinct()
            .ToList();

        result.ForEach(Console.WriteLine);

        Console.ReadLine();
    }

public sealed class Result : IEqualityComparer<Result>
{
    public int DeviceId { get; set; }

    public int ActionType { get; set; }

    public bool Equals(Result x, Result y)
    {
        if (ReferenceEquals(x, y)) return true;
        if (ReferenceEquals(x, null)) return false;
        if (ReferenceEquals(y, null)) return false;
        if (x.GetType() != y.GetType()) return false;
        return x.DeviceId == y.DeviceId && x.ActionType == y.ActionType;
    }

    public int GetHashCode(Result obj)
    {
        unchecked
        {
            return (obj.DeviceId*397) ^ obj.ActionType;
        }
    }

    public override string ToString()
    {
        return string.Format("DeviceId: {0}, ActionType: {1}", DeviceId, ActionType);
    }
}

Result output:

DeviceId: 2, ActionType: 1
DeviceId: 3, ActionType: 1
DeviceId: 4, ActionType: 1
DeviceId: 5, ActionType: 1

Upvotes: 0

Konrad Kokosa
Konrad Kokosa

Reputation: 16878

Besides answer with query syntax, in method syntax LINQ query it will be:

results = results.GroupBy(r => r.DeviceId)
                 .Where(g => g.Key != 1 && g.Count() == 1)
                 .Select(g => g.First())
                 .ToList();

Upvotes: 1

MarcinJuraszek
MarcinJuraszek

Reputation: 125630

results =  from r in results
           group r by r.DeviceId into g
           where g.Count() == 1
           select g.First()

You can make it a little bit more efficient replacing g.Count() with !g.Skip(1).Any():

results =  from r in results
           group r by r.DeviceId into g
           where !g.Skip(1).Any()
           select g.First()

It will return false as soon as second element is found, instead of counting all items in the group.

Upvotes: 1

Theraot
Theraot

Reputation: 40200

After grouping you can select the first (and only element of the group):

results =  from result in results
          group result by result.DeviceId
          into groupedResultsByDevice
          where groupedResultsByDevice.Count() == 1
          select groupedResultsByDevice.First(); // <---

Upvotes: 1

Related Questions