Michele Boscagin
Michele Boscagin

Reputation: 97

Select most repeated item by element

I'm trying to get 3 related articles with most tags in common with the main article. I have this DB struct:

StructDB

When I get the main article, I get the tags related to the article. Then, I pass the IDArticle and the TagList of the article to the function for get the related 3 articles.
The list That acts as glue between Article and Tags is the ArticoloTag, and I think that is the list to check for get the article with most repeated tags in common.
Obviously I think is better to develop this algorithm on server side with c#. How to do this with linq?
Thanks for help

Upvotes: 0

Views: 134

Answers (4)

Frogger
Frogger

Reputation: 185

Not sure if this is inefficient but you can try something like this (searchTagList is the given article's tag list )

var relavantList = articleList.
            Select(a => new {
                artical = a,
                relevancyCount = a.ArticoloTag.Where(tag => searchTagList.Contains(tag)).Count()
            }).
            ToList().
            OrderByDescending(a => a.relevancyCount).
            ThenBy(a => a.artical.Title). //if similar relevancy then ordered by title
            Take(3).ToList();

Below is the data structure I used.

class Articolo {

    public int ID { get; set; }

    public List<Tag> ArticoloTag { get; set; }

    public string Title { get; set; }

}

class Tag {

    public int ID { get; set; }

    public string TagText { get; set; }
}

Upvotes: 1

Fredrik Lundin Grande
Fredrik Lundin Grande

Reputation: 8186

One way of doing it could be to:

  1. Extract the tags from your main article
  2. Find other articles using that tag
  3. Keep a dictionary for the articles found and increment a counter for each matching tag
  4. Order the dictionary and take the top 3 results

    static void Main(string[] args)
    {
        var articleTags = new List<ArticleTag>
        {
            new ArticleTag(1, "a"),
            new ArticleTag(1, "b"),
            new ArticleTag(1, "c"),
            new ArticleTag(2, "a"),
            new ArticleTag(2, "b"),
            new ArticleTag(3, "a"),
            new ArticleTag(4, "b"),
            new ArticleTag(4, "c"),
            new ArticleTag(5, "a"),
            new ArticleTag(5, "b"),
            new ArticleTag(5, "c"),
        };
    
        var resultDict = new Dictionary<int, int>(); // Where we store the result
        const int mainArticleId = 1; // Your main article
        var tagsFromMainArticle = articleTags.Where(x => x.Id == mainArticleId).Select(x => x.Tag).ToList(); // All tags on the main article
    
        tagsFromMainArticle.ForEach(tag => 
            articleTags
                .Where(a => a.Tag == tag && a.Id != mainArticleId)
                .ToList()
                .ForEach(x =>
                {
                    if (resultDict.ContainsKey(x.Id)) resultDict[x.Id]++;
                    else resultDict[x.Id] = 1;
                }));
    
        foreach (var resultKeyValuePair in resultDict.OrderByDescending(v => v.Value).Take(3))
        {
            Console.WriteLine($"Key = {resultKeyValuePair.Key}, Value = {resultKeyValuePair.Value}");
        }
    }
    

Here is the simple ArticleTag class for the example

public class ArticleTag
{
    public ArticleTag(int id, string tag)
    {
       Id = id;
       Tag = tag;
    }

    public int Id { get; private set; }
    public string Tag { get; private set; }
}

Upvotes: 0

Riaan Swart
Riaan Swart

Reputation: 293

I may misunderstand your question but when you want to get data from a table that shares relational tables you will need to start from the lowest table and work back up in groupings. You will have to do your on DB code here as I have no idea what you will use. This is not actual compile code but guidance code:

var list = dbConext.Tag.Where([your filter]).SelectMany( i => i.ArticoloTags).GroupBy(i => i.IDTag).OrderBy(i=>i.Count()).ToList();

From this list you can do what you want.

Upvotes: 1

Ofir Winegarten
Ofir Winegarten

Reputation: 9365

In order to find the top 3 articles with most tags in common you can use the ArticoloTag and join itself on the IdTag

The linq can look like this:

ArticoloTag.Where (a=>a.IdArticolo== mainArticleId).Join(ArticoloTag, a=>a.IdTag, a=>a.IdTag, (a,b)=> b.IdArticolo).GroupBy(a=>a.IdArticolo).OrderBy(g=>g.Count()).Select(g => g.Key).Take(3)

This will get back the your 3 IdArticle.

You can add a join to the Articolo table to get the actual articles

Upvotes: 1

Related Questions