简体   繁体   中英

Getting the count of most repeated records in Linq

I am working on an application in which I have to store play history of a song in the data table. I have a table named PlayHistory which has four columns.

Id | SoundRecordingId(FK) | UserId(FK) | DateTime

Now i have to implement a query that will return the songs that are in trending phase ie being mostly played. I have written the following query in sql server that returns me data somehow closer to what I want.

select  COUNT(*) as High,SoundRecordingId
from PlayHistory
where DateTime >= GETDATE()-30
group by  SoundRecordingId
Having COUNT(*) > 1
order by SoundRecordingId desc

It returned me following data:

High  SoundRecordingId
2       5
2       3

Which means Song with Ids 5 and 3 were played the most number of times ie2 How can I implement this through Linq in c#. I have done this so far:

        DateTime d = DateTime.Now;
        var monthBefore = d.AddMonths(-1);
        var list =
            _db.PlayHistories
            .OrderByDescending(x=>x.SoundRecordingId)
            .Where(t => t.DateTime >= monthBefore)
            .GroupBy(x=>x.SoundRecordingId)
            .Take(20)
            .ToList();

It returns me list of whole table with the count of SoundRecording objects but i want just count of the most repeated records. Thanks

I like the 'linq' syntax it's similar to SQL

var query = from history in _db.PlayHistories
            where history.DateTime >= monthBefore
            group history by history.SoundRecordingId into historyGroup
            where historyGroup.Count() > 1
            orderby historyGroup.Key
            select new { High = historyGroup.Count(), SoundRecordingId = historyGroup.Key };

var data = query.Take(20).ToList();

There is an overload of the .GroupBy method which will solve your problem.

DateTime d = DateTime.Now;
    var monthBefore = d.AddMonths(-1);
    var list =
        _db.PlayHistories
        .OrderByDescending(x=>x.SoundRecordingId)
        .Where(t => t.DateTime >= monthBefore)

        .GroupBy(x=>x.SoundRecordingId, (key,values) => new {SoundRecordingID=key, High=values.count()})

        .Take(20)
        .ToList();

I have simply added the result selector to the GroupBy method call here which does the same transformation you have written in your SQL.

The method overload in question is documented here

To go further into your problem, you will probably want to do another OrderByDescending to get your results in popularity order. To match the SQL statement you also have to filter for only counts > 1.

DateTime d = DateTime.Now;
    var monthBefore = d.AddMonths(-1);
    var list =
        _db.PlayHistories
        .Where(t => t.DateTime >= monthBefore)
        .GroupBy(x=>x.SoundRecordingId, (key,values) => new {SoundRecordingID=key, High=values.count()})
        .Where(x=>x.High>1)
        .OrderByDescending(x=>x.High)
        .ToList();

You´re allmost done. Just order your list by the count and take the first:

var max =
        _db.PlayHistories
        .OrderByDescending(x=>x.SoundRecordingId)
        .Where(t => t.DateTime >= monthBefore)
        .GroupBy(x=>x.SoundRecordingId)
        .OrderByDescending(x => x.Count())
        .First();

This gives you a single key-value-pair where the Key is your SoundRecordingId and the value is the number of its occurences in your input-list.

EDIT: To get all records with that amount chose this instead:

var grouped =
        _db.PlayHistories
        .OrderByDescending(x => x.SoundRecordingId)
        .Where(t => t.DateTime >= monthBefore)
        .GroupBy(x => x.SoundRecordingId)
        .Select(x => new { Id = x.Key, Count = x.Count() }
        .OrderByDescending(x => x.Count)
        .ToList();
var maxCount = grouped.First().Count;
var result = grouped.Where(x => x.Count == maxCount);

This solves the problem by giving you what you asked for. Your query in LINQ, returning just the play counts.

var list = _db.PlayHistories.Where(x => x.DateTimeProp > (DateTime.Now).AddMonths(-1))
           .OrderByDescending(y => y.SoundRecordingId.Count())
           .ThenBy(z => z.SoundRecordingId)
           .Select(xx => xx.SoundRecordingId).Take(20).ToList();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM