More efficient and readable nested loop to compare keywords
Note: last refactoring with rich domain model approach is at the bottom. But you can see my 3 refactoring steps which lead to nice object-oriented design.

You can use Linq to make your code more readable. Also you can give names for intermediate results:

var articlesWithRoles = from a in articles
                        where a.Roles != null &amp;&amp; a.Roles.Any()
                        select a;

var primaryRole = roles.First().ToLower();

var highWeightArticles = from a in articlesWithRoles
                         where a.Roles.First().ToLower() == primaryRole
                         select a;

foreach(var article in highWeightArticles)
    article.Weight += 3;

var lowWeightArticles = from a in articlesWithRoles.Except(highWeightArticles)
                        from ar in a.Roles
                        join r in roles on ar.ToLower() equals r.ToLower()
                        select a;

foreach(var article in lowWeightArticles)
    article.Weight += 1;

var articlesWithTopics = from a in articles
                         where a.Topics != null
                         from at in a.Topics
                         join t in topics on at.ToLower() equals t.ToLower()
                         select a;

foreach(var article in articlesWithTopics)
    article.Weight += 0.8;


I also would recommend to use named constants instead of magic numbers 3, 1, 0.8. Also maybe you don't need to create new list, because it will share same articles as list yo passed to method.



Further improving readability could involve splitting this method into three methods:

 AddRolesWeights(articles, roles);
 AddPrimaryRoleWeights(articles, roles.First());
 AddTopicsWeights(articles, topics);


Which could look this way:

void AddRolesWeights(IEnumerable&lt;Article&gt; articles, IEnumerable&lt;Role&gt; roles)
{
    const double RoleWeight = 1;

    var nonPrimaryArticles = 
        from a in articles
        where a.Roles != null &amp;&amp; a.Roles.Any() &amp;&amp;
        from ar in a.Roles
        join r in roles on ar.ToLower() equals r.ToLower()
        select a;

    foreach(var article in primaryArticles)
        article.Weight += RoleWeight;
}


Yes, its less efficient. But you always should chose between readability and performance:

void AddPrimaryRoleWeights(IEnumerable&lt;Article&gt; articles, string primaryRole)
{
    const double PrimaryArticleWeight = 2;
    var primaryArticles = 
       from a in articlesWithRoles
       where a.Roles != null &amp;&amp; a.Roles.Any() &amp;&amp;
           String.Equals(a.Roles[0], primaryRole, StringComparison.CurrentCultureIgnoreCase)
       select a;

    foreach(var article in primaryArticles)
        article.Weight +=  PrimaryArticleWeight;
}


Same way you can update articles with selected topics.



Final solution

Further refactoring can include moving weights calculation logic to article class, thus making it reach instead of anemic, and increasing cohesion:

 // add this to Article class
 public double Weight { get; private set; } // probably you don't need setter

 public void AddWeights(IEnumerable&lt;Role&gt; roles)
 {
     const double RoleWeight = 1;
     const double PrimaryRoleWeight = 3;

     if (!roles.Any())
        return;

     if (Roles == null || !Roles.Any())
         return;

     var pirmaryRole = roles.First();
     if (String.Equals(Roles[0], primaryRole, StringComparison.CurrentCultureIgnoreCase))
     {
         Weight += PrimaryRoleWeight;
         return;
     }

     foreach(var role in roles)         
        if (Roles.Contains(role, StringComparer.CurrentCultureIgnoreCase))
            Weight += RoleWeight;
 }


Adding topics weights:

 public void AddWeights(IEnumerable&lt;Topic&gt; topics)
 {
     const double TopicWeight = 0.8;

     if (Topics == null || !Topics.Any() || !topics.Any())
        return;

     foreach(var topic in topics)         
        if (Topics.Contains(topic, StringComparer.CurrentCultureIgnoreCase))
            Weight += TopicWeight;
 }


And your original code will look like:

 foreach(var article in articles)
 {
     article.AddWeights(roles);
     article.AddWeights(topics);
 }


I think it's a little more readable now :)