Reputation: 97
I'm trying to get 3 related articles with most tags in common with the main article. I have this DB struct:
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
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
Reputation: 8186
One way of doing it could be to:
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
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
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