Piotr P
Piotr P

Reputation: 97

Select first element that has certain property if there are any duplicates otherwise select first element

For example I have a list of objects, with those properties

{ ID: "1", STATUS: "INA" }
{ ID: "1", STATUS: "ACT" } 
{ ID: "2", STATUS: "INA" } 
{ ID: "2", STATUS: "BLO" }

And now I want to group them by ID, to reduce duplicates, but when the duplicates are found I want to check if any of the statuses is ACT, if it is ACT i want to select this record, but if there's no ACT status I want to select first occurrence of the duplicate.

In example above I would want to select

{ ID: "1", STATUS: "ACT" } //since it has ACT
{ ID: "2", STATUS: "INA" } //since it is first duplicate found

I know that the first step would be

var NoDup = from l in list.AsEnumerable()
                  group l by l.ID into c

But I don't know what to do next

Upvotes: 3

Views: 1077

Answers (4)

Ipsit Gaur
Ipsit Gaur

Reputation: 2927

var NoDup = from l in list.AsEnumerable()
                  group l by l.ID into c
                  select c.FirstOrDefault(x => x.STATUS == "ACT") ?? 
                               c.FirstOrDefault()

Upvotes: 3

Tim Schmelter
Tim Schmelter

Reputation: 460108

var q = list.GroupBy(x => x.ID)
            .Select(g => g.OrderByDescending(x => x.STATUS == "ACT").First());

So first group-by the ID, then order the groups by the bool that is returned from the comparison x.STATUS == "ACT". True is "higher" than false, that's why i used OrderByDescending. First ensures that i only get the first record of every duplicate-group. Since OrderBy... has a stable sort the original order is maintained even if there is no ACT-status.


Another similar approach which might be little bit more efficient is:

var q = list.GroupBy(x => x.ID)
    .Select(g => g.Where(x => x.STATUS == "ACT").DefaultIfEmpty(g.First()).First());

This could be more efficient if the duplicae-groups are very large because the whole group doesn't need to be ordered by the bool if the first was already STATUS == "ACT".

Upvotes: 8

Codor
Codor

Reputation: 17605

It could be done as follows.

List
  .GroupBy( iLine =>
            iLine.ID )
  .Select( iGroup =>
           iGroup .FirstOrDefault( jLine => jLine.Status == "ACK" ? ) ?? iGroup.First() );

Upvotes: 0

qxg
qxg

Reputation: 7036

from l in list
group l by l.ID into c
select c.FirstOrDefault(i => i.STATUS == "ACT") ?? c.First()

Upvotes: 2

Related Questions