Reputation: 419
I was wondering if you could help.
I have a list of information;
ClientNo SequenceNo
This could contain data such as;
Cli No: 0000001, seq: 1
Cli No: 0000001, seq: 2
Cli No: 0000001, seq: 3
Cli No: 0000001, seq: 3
Cli No: 0000002, seq: 1
Cli No: 0000002, seq: 1
Cli No: 0000002, seq: 2
Cli No: 0000002, seq: 2
I want to generate a list of the max sequence numbers.
Please note that the sequence number MAY be repeated numerous times, as per the example above.
So the list I would like to end up with from example about would be;
Cli No: 0000001, seq: 3
Cli No: 0000001, seq: 3
Cli No: 0000002, seq: 2
Cli No: 0000002, seq: 2
I have tried;
var x = criticalNotesData.OrderBy(y => y.ClientNo)
.ThenBy(z => z.SequenceNo).ToList();
var m = x.Max(r => r.SequenceNo).ToList();
But the max is just providing the max sequence no in the list, rather than per client.
Thanks,
David
Upvotes: 1
Views: 2292
Reputation: 3425
Assuming data like this:
var list = new []
{
new { CliNo= "0000001", SeqNo= 1 },
new { CliNo= "0000001", SeqNo= 2 },
new { CliNo= "0000002", SeqNo= 1 },
new { CliNo= "0000001", SeqNo= 3 },
new { CliNo= "0000001", SeqNo= 3 },
new { CliNo= "0000002", SeqNo= 1 },
new { CliNo= "0000002", SeqNo= 1 },
new { CliNo= "0000002", SeqNo= 2 },
new { CliNo= "0000002", SeqNo= 2 },
};
you can use this:
var output =
from i in list
orderby i.CliNo, i.SeqNo
group i by i.CliNo into g
let max = g.Max(x => x.SeqNo)
from r in g where r.SeqNo == max
select r;
Is still valid what I said in a comment, the initial order of the data is important, in this code I took a general approach, but if you have guarantees about the initial order there are other strategies which can be more efficient if your source of data is expensive.
Upvotes: 0
Reputation: 75306
use GroupBy
twice then OrderByDescending
to get First
instead of using Max
, with this way, you don't need to create new object and still get the duplicate max items
var result = criticalNotesData.GroupBy(x => x.ClientNo)
.SelectMany(g => g.GroupBy(y => y.SequenceNo)
.OrderByDescending(gg => gg.Key)
.First()
);
The result will be exactly what you want:
Cli No: 0000001, seq: 3
Cli No: 0000001, seq: 3
Cli No: 0000002, seq: 2
Cli No: 0000002, seq: 2
Upvotes: 3
Reputation: 15015
You want, for each of the 'Client' entries, to know the highest sequence. Thus that means the result should be a sequence (per client) rather than a single value as returned by Max. How about:
var maxSequence = criticalNotesData
.GroupBy(n => n.ClientNo)
.Select(g => new { Client = g.Key, Max = g.Max(i => i.SequenceNo) } );
foreach ( var entry in maxSequence )
{
Console.WriteLine("Client {0} has max sequence of {1}",
entry.Client, entry.Max);
}
// Looking at your original, you now want only to know the (from the original)
// the entries matching MAX. Since you now know the max per client, a second
// operation is needed.
var maxValueEntries = criticalNotesData
.Where(n => maxSequence
.Single(c => c.Client == n.Client)
.Max == n.SequenceNo));
The maxValueEntries
is doing a lot of lookups, so a Dictionary of values may be better.
// Turning the original into a Dictionary of clientNo returning the
// max sequence.
var maxSequence2 = criticalNotesData
.GroupBy(n => n.ClientNo)
.Select(g => new { Client = g.Key, Max = g.Max(i => i.SequenceNo) } )
.ToDictionary(c => c.Client, c => c.Max);
var maxValueEntries2 = criticalNotesData
.Where(n => maxSequence2[n.Client] == n.SequenceNo));
Upvotes: 0
Reputation: 2666
you need GroupBy
var maxItems = criticalNotesData.GroupBy(p => p.ClientNo)
.Select(r => r.Max(q => q.SeqNo));
something like this.
or
var maxItemsClientWise = from p in criticalNotesData
group p by p.ClientNo into r
select new { MaxSeq = r.Max(g => g.SeqNo),
Client = r.First().ClientNo };
Upvotes: 1
Reputation: 223247
You can use the following query to get a list of your class object based on your criteria.
var query = (from t in list
group t by t.CliNo into tgroup
select new ClientSequence
{
CliNo = tgroup.Key,
seq = tgroup.Max(r => r.seq)
}).ToList();
It is assuming that your class structure is:
class ClientSequence
{
public string CliNo { get; set; }
public int seq { get; set; }
}
and your list is:
List<ClientSequence> list = new List<ClientSequence>
{
new ClientSequence{ CliNo= "0000001", seq= 1},
new ClientSequence{ CliNo= "0000001", seq= 2},
new ClientSequence{ CliNo= "0000001", seq= 3},
new ClientSequence{ CliNo= "0000002", seq= 1},
new ClientSequence{ CliNo= "0000002", seq= 1},
new ClientSequence{ CliNo= "0000002", seq= 1},
new ClientSequence{ CliNo= "0000002", seq= 2},
new ClientSequence{ CliNo= "0000002", seq= 2},
};
Output:
foreach (ClientSequence cs in query)
{
Console.Write("Client No.: " + cs.CliNo);
Console.WriteLine(" Max Sequence No.: " + cs.seq);
}
It will print
Client No.: 0000001 Max Sequence No.: 3
Client No.: 0000002 Max Sequence No.: 2
Upvotes: 1
Reputation: 3761
I can't try but I think this should work!
var m = x.GroupBy(r => r.ClientNo).Select(g => g.Max(x => x.SequenceNo));
EDIT: to know the client:
var m = x.GroupBy(r => r.ClientNo).Select(g => new { ClientID = g.Key, Max = g.Max(x => x.SequenceNo) });
Upvotes: 1