Most efficient way to loop through two C# Lists












-1















I have a method which I call CalculatePopularityScore. It exists on a Story object. The Story object has a field which is an ICollection of Comment objects.



public virtual ICollection<Comment> Comments { get; set; }


The Comment object has another collection of Reply objects.



My method looks at the story, loops through the comments associated with that story, and if the story's comments has replies, adds up that total. That, along with some other fields, gives me a very (and I stress this) very rudimentary algorithm of a story's popularity.



public double CalculateStoryPopularityScore()
{
if (Comments == null) throw new ArgumentException("Comments can't be null");
if (Comments.Count < 0) throw new ArgumentException("Comments can't be less than zero.");

int ReplyCountSum = 0;
double ReplyScore;
double CommentScore;
double InsightfulVoteScore;
double UsefulVoteScore;
double viewCount;

foreach (var comment in Comments)
{
int replyCount;

if (comment.Replies == null)
{
throw new ArgumentNullException("Replies cannot be null");
}

if (comment.Replies.Count() == 0)
{
replyCount = 0;
} else
{
replyCount = comment.Replies.Count();
}

ReplyCountSum += replyCount;
}

ReplyScore = ReplyCountSum * 4;
CommentScore = Comments.Count() * 4;
InsightfulVoteScore = InsightFulVoteCount * 3;
UsefulVoteScore = UsefulVoteCount * 2;
viewCount = ViewCount;

double PopularityScore = CommentScore + ReplyScore + InsightfulVoteScore + + UsefulVoteScore + viewCount;
return PopularityScore;
}


This seems to work fine. Now, what I'd like to do is take this method and apply it to a number of stories (i.e. a list).



I currently have this method written. It has not yet implemented another loop to look through the replies to the comments collection of a story. I know nested loops are considered bad and slow. What would be the most efficient way to look at the list of stories, then the list of comments in each story, add up those replies, and calculate a story's popularity score?



public void CalculateStoryPopularityScore(List<Story> stories)
{
if (stories == null) throw new ArgumentException("Stories can't be null");

double CommentScore;
double InsightfulVoteScore;
double UsefulVoteScore;
double PopularityScore;
double ViewCount;

foreach (var story in stories)
{
CommentScore = story.Comments.Count() * 4;
InsightfulVoteScore = story.InsightFulVoteCount * 3;
UsefulVoteScore = story.UsefulVoteCount * 2;
ViewCount = story.ViewCount;

PopularityScore = CommentScore + InsightfulVoteScore + UsefulVoteScore + ViewCount;
story.PopularityScore = PopularityScore;
}
}









share|improve this question

























  • This sounds like something you should be doing in the DB/DB query, not in the code. A "currentValue" that is updated via a Add/Update Trigger on the Comments table ora view can both be used to cache such data. Doing this operation every time the page is draw or a postback of this page appears is just a massive waste of resources.

    – Christopher
    Nov 14 '18 at 22:51













  • You can also consider using Dictionaries to help avoid inner loops.

    – Drew Kennedy
    Nov 14 '18 at 22:52











  • I know nested loops are considered bad and slow have you measured? is it really slow for your purposes? How big are your data? And how often this calculation needs to happen?

    – trailmax
    Nov 14 '18 at 22:54











  • Note that I am normally very firmly about "not putting process data into the DB". But something like "StoryPopularityScore" based on comments (often querried, very rarely changed) just screams for some for of caching.

    – Christopher
    Nov 14 '18 at 22:55






  • 1





    By the way, it doesn't make any sense to throw an ArgumentException from a method that doesn't take any arguments (in the first example). You should probably re-write it so that the comments are passed in as a parameter. Also, local variables should be camelCase, not PascalCase in c#. :)

    – Rufus L
    Nov 15 '18 at 0:03


















-1















I have a method which I call CalculatePopularityScore. It exists on a Story object. The Story object has a field which is an ICollection of Comment objects.



public virtual ICollection<Comment> Comments { get; set; }


The Comment object has another collection of Reply objects.



My method looks at the story, loops through the comments associated with that story, and if the story's comments has replies, adds up that total. That, along with some other fields, gives me a very (and I stress this) very rudimentary algorithm of a story's popularity.



public double CalculateStoryPopularityScore()
{
if (Comments == null) throw new ArgumentException("Comments can't be null");
if (Comments.Count < 0) throw new ArgumentException("Comments can't be less than zero.");

int ReplyCountSum = 0;
double ReplyScore;
double CommentScore;
double InsightfulVoteScore;
double UsefulVoteScore;
double viewCount;

foreach (var comment in Comments)
{
int replyCount;

if (comment.Replies == null)
{
throw new ArgumentNullException("Replies cannot be null");
}

if (comment.Replies.Count() == 0)
{
replyCount = 0;
} else
{
replyCount = comment.Replies.Count();
}

ReplyCountSum += replyCount;
}

ReplyScore = ReplyCountSum * 4;
CommentScore = Comments.Count() * 4;
InsightfulVoteScore = InsightFulVoteCount * 3;
UsefulVoteScore = UsefulVoteCount * 2;
viewCount = ViewCount;

double PopularityScore = CommentScore + ReplyScore + InsightfulVoteScore + + UsefulVoteScore + viewCount;
return PopularityScore;
}


This seems to work fine. Now, what I'd like to do is take this method and apply it to a number of stories (i.e. a list).



I currently have this method written. It has not yet implemented another loop to look through the replies to the comments collection of a story. I know nested loops are considered bad and slow. What would be the most efficient way to look at the list of stories, then the list of comments in each story, add up those replies, and calculate a story's popularity score?



public void CalculateStoryPopularityScore(List<Story> stories)
{
if (stories == null) throw new ArgumentException("Stories can't be null");

double CommentScore;
double InsightfulVoteScore;
double UsefulVoteScore;
double PopularityScore;
double ViewCount;

foreach (var story in stories)
{
CommentScore = story.Comments.Count() * 4;
InsightfulVoteScore = story.InsightFulVoteCount * 3;
UsefulVoteScore = story.UsefulVoteCount * 2;
ViewCount = story.ViewCount;

PopularityScore = CommentScore + InsightfulVoteScore + UsefulVoteScore + ViewCount;
story.PopularityScore = PopularityScore;
}
}









share|improve this question

























  • This sounds like something you should be doing in the DB/DB query, not in the code. A "currentValue" that is updated via a Add/Update Trigger on the Comments table ora view can both be used to cache such data. Doing this operation every time the page is draw or a postback of this page appears is just a massive waste of resources.

    – Christopher
    Nov 14 '18 at 22:51













  • You can also consider using Dictionaries to help avoid inner loops.

    – Drew Kennedy
    Nov 14 '18 at 22:52











  • I know nested loops are considered bad and slow have you measured? is it really slow for your purposes? How big are your data? And how often this calculation needs to happen?

    – trailmax
    Nov 14 '18 at 22:54











  • Note that I am normally very firmly about "not putting process data into the DB". But something like "StoryPopularityScore" based on comments (often querried, very rarely changed) just screams for some for of caching.

    – Christopher
    Nov 14 '18 at 22:55






  • 1





    By the way, it doesn't make any sense to throw an ArgumentException from a method that doesn't take any arguments (in the first example). You should probably re-write it so that the comments are passed in as a parameter. Also, local variables should be camelCase, not PascalCase in c#. :)

    – Rufus L
    Nov 15 '18 at 0:03
















-1












-1








-1








I have a method which I call CalculatePopularityScore. It exists on a Story object. The Story object has a field which is an ICollection of Comment objects.



public virtual ICollection<Comment> Comments { get; set; }


The Comment object has another collection of Reply objects.



My method looks at the story, loops through the comments associated with that story, and if the story's comments has replies, adds up that total. That, along with some other fields, gives me a very (and I stress this) very rudimentary algorithm of a story's popularity.



public double CalculateStoryPopularityScore()
{
if (Comments == null) throw new ArgumentException("Comments can't be null");
if (Comments.Count < 0) throw new ArgumentException("Comments can't be less than zero.");

int ReplyCountSum = 0;
double ReplyScore;
double CommentScore;
double InsightfulVoteScore;
double UsefulVoteScore;
double viewCount;

foreach (var comment in Comments)
{
int replyCount;

if (comment.Replies == null)
{
throw new ArgumentNullException("Replies cannot be null");
}

if (comment.Replies.Count() == 0)
{
replyCount = 0;
} else
{
replyCount = comment.Replies.Count();
}

ReplyCountSum += replyCount;
}

ReplyScore = ReplyCountSum * 4;
CommentScore = Comments.Count() * 4;
InsightfulVoteScore = InsightFulVoteCount * 3;
UsefulVoteScore = UsefulVoteCount * 2;
viewCount = ViewCount;

double PopularityScore = CommentScore + ReplyScore + InsightfulVoteScore + + UsefulVoteScore + viewCount;
return PopularityScore;
}


This seems to work fine. Now, what I'd like to do is take this method and apply it to a number of stories (i.e. a list).



I currently have this method written. It has not yet implemented another loop to look through the replies to the comments collection of a story. I know nested loops are considered bad and slow. What would be the most efficient way to look at the list of stories, then the list of comments in each story, add up those replies, and calculate a story's popularity score?



public void CalculateStoryPopularityScore(List<Story> stories)
{
if (stories == null) throw new ArgumentException("Stories can't be null");

double CommentScore;
double InsightfulVoteScore;
double UsefulVoteScore;
double PopularityScore;
double ViewCount;

foreach (var story in stories)
{
CommentScore = story.Comments.Count() * 4;
InsightfulVoteScore = story.InsightFulVoteCount * 3;
UsefulVoteScore = story.UsefulVoteCount * 2;
ViewCount = story.ViewCount;

PopularityScore = CommentScore + InsightfulVoteScore + UsefulVoteScore + ViewCount;
story.PopularityScore = PopularityScore;
}
}









share|improve this question
















I have a method which I call CalculatePopularityScore. It exists on a Story object. The Story object has a field which is an ICollection of Comment objects.



public virtual ICollection<Comment> Comments { get; set; }


The Comment object has another collection of Reply objects.



My method looks at the story, loops through the comments associated with that story, and if the story's comments has replies, adds up that total. That, along with some other fields, gives me a very (and I stress this) very rudimentary algorithm of a story's popularity.



public double CalculateStoryPopularityScore()
{
if (Comments == null) throw new ArgumentException("Comments can't be null");
if (Comments.Count < 0) throw new ArgumentException("Comments can't be less than zero.");

int ReplyCountSum = 0;
double ReplyScore;
double CommentScore;
double InsightfulVoteScore;
double UsefulVoteScore;
double viewCount;

foreach (var comment in Comments)
{
int replyCount;

if (comment.Replies == null)
{
throw new ArgumentNullException("Replies cannot be null");
}

if (comment.Replies.Count() == 0)
{
replyCount = 0;
} else
{
replyCount = comment.Replies.Count();
}

ReplyCountSum += replyCount;
}

ReplyScore = ReplyCountSum * 4;
CommentScore = Comments.Count() * 4;
InsightfulVoteScore = InsightFulVoteCount * 3;
UsefulVoteScore = UsefulVoteCount * 2;
viewCount = ViewCount;

double PopularityScore = CommentScore + ReplyScore + InsightfulVoteScore + + UsefulVoteScore + viewCount;
return PopularityScore;
}


This seems to work fine. Now, what I'd like to do is take this method and apply it to a number of stories (i.e. a list).



I currently have this method written. It has not yet implemented another loop to look through the replies to the comments collection of a story. I know nested loops are considered bad and slow. What would be the most efficient way to look at the list of stories, then the list of comments in each story, add up those replies, and calculate a story's popularity score?



public void CalculateStoryPopularityScore(List<Story> stories)
{
if (stories == null) throw new ArgumentException("Stories can't be null");

double CommentScore;
double InsightfulVoteScore;
double UsefulVoteScore;
double PopularityScore;
double ViewCount;

foreach (var story in stories)
{
CommentScore = story.Comments.Count() * 4;
InsightfulVoteScore = story.InsightFulVoteCount * 3;
UsefulVoteScore = story.UsefulVoteCount * 2;
ViewCount = story.ViewCount;

PopularityScore = CommentScore + InsightfulVoteScore + UsefulVoteScore + ViewCount;
story.PopularityScore = PopularityScore;
}
}






c#






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 14 '18 at 23:17









Erik Philips

41.1k691124




41.1k691124










asked Nov 14 '18 at 22:47









J.G.SableJ.G.Sable

254213




254213













  • This sounds like something you should be doing in the DB/DB query, not in the code. A "currentValue" that is updated via a Add/Update Trigger on the Comments table ora view can both be used to cache such data. Doing this operation every time the page is draw or a postback of this page appears is just a massive waste of resources.

    – Christopher
    Nov 14 '18 at 22:51













  • You can also consider using Dictionaries to help avoid inner loops.

    – Drew Kennedy
    Nov 14 '18 at 22:52











  • I know nested loops are considered bad and slow have you measured? is it really slow for your purposes? How big are your data? And how often this calculation needs to happen?

    – trailmax
    Nov 14 '18 at 22:54











  • Note that I am normally very firmly about "not putting process data into the DB". But something like "StoryPopularityScore" based on comments (often querried, very rarely changed) just screams for some for of caching.

    – Christopher
    Nov 14 '18 at 22:55






  • 1





    By the way, it doesn't make any sense to throw an ArgumentException from a method that doesn't take any arguments (in the first example). You should probably re-write it so that the comments are passed in as a parameter. Also, local variables should be camelCase, not PascalCase in c#. :)

    – Rufus L
    Nov 15 '18 at 0:03





















  • This sounds like something you should be doing in the DB/DB query, not in the code. A "currentValue" that is updated via a Add/Update Trigger on the Comments table ora view can both be used to cache such data. Doing this operation every time the page is draw or a postback of this page appears is just a massive waste of resources.

    – Christopher
    Nov 14 '18 at 22:51













  • You can also consider using Dictionaries to help avoid inner loops.

    – Drew Kennedy
    Nov 14 '18 at 22:52











  • I know nested loops are considered bad and slow have you measured? is it really slow for your purposes? How big are your data? And how often this calculation needs to happen?

    – trailmax
    Nov 14 '18 at 22:54











  • Note that I am normally very firmly about "not putting process data into the DB". But something like "StoryPopularityScore" based on comments (often querried, very rarely changed) just screams for some for of caching.

    – Christopher
    Nov 14 '18 at 22:55






  • 1





    By the way, it doesn't make any sense to throw an ArgumentException from a method that doesn't take any arguments (in the first example). You should probably re-write it so that the comments are passed in as a parameter. Also, local variables should be camelCase, not PascalCase in c#. :)

    – Rufus L
    Nov 15 '18 at 0:03



















This sounds like something you should be doing in the DB/DB query, not in the code. A "currentValue" that is updated via a Add/Update Trigger on the Comments table ora view can both be used to cache such data. Doing this operation every time the page is draw or a postback of this page appears is just a massive waste of resources.

– Christopher
Nov 14 '18 at 22:51







This sounds like something you should be doing in the DB/DB query, not in the code. A "currentValue" that is updated via a Add/Update Trigger on the Comments table ora view can both be used to cache such data. Doing this operation every time the page is draw or a postback of this page appears is just a massive waste of resources.

– Christopher
Nov 14 '18 at 22:51















You can also consider using Dictionaries to help avoid inner loops.

– Drew Kennedy
Nov 14 '18 at 22:52





You can also consider using Dictionaries to help avoid inner loops.

– Drew Kennedy
Nov 14 '18 at 22:52













I know nested loops are considered bad and slow have you measured? is it really slow for your purposes? How big are your data? And how often this calculation needs to happen?

– trailmax
Nov 14 '18 at 22:54





I know nested loops are considered bad and slow have you measured? is it really slow for your purposes? How big are your data? And how often this calculation needs to happen?

– trailmax
Nov 14 '18 at 22:54













Note that I am normally very firmly about "not putting process data into the DB". But something like "StoryPopularityScore" based on comments (often querried, very rarely changed) just screams for some for of caching.

– Christopher
Nov 14 '18 at 22:55





Note that I am normally very firmly about "not putting process data into the DB". But something like "StoryPopularityScore" based on comments (often querried, very rarely changed) just screams for some for of caching.

– Christopher
Nov 14 '18 at 22:55




1




1





By the way, it doesn't make any sense to throw an ArgumentException from a method that doesn't take any arguments (in the first example). You should probably re-write it so that the comments are passed in as a parameter. Also, local variables should be camelCase, not PascalCase in c#. :)

– Rufus L
Nov 15 '18 at 0:03







By the way, it doesn't make any sense to throw an ArgumentException from a method that doesn't take any arguments (in the first example). You should probably re-write it so that the comments are passed in as a parameter. Also, local variables should be camelCase, not PascalCase in c#. :)

– Rufus L
Nov 15 '18 at 0:03














2 Answers
2






active

oldest

votes


















0














Use SelectMany



var commentCount = story.Comments.Count();

// count all replies to all comments for a story
var replyCountSum = story.Comments
.SelectMany(c => c.Replies)
.Count();


Apply to a collection of stories:



stories.Select(s => new
{
Story = s,
CommentCount = s.Comments.Count(),
ReplyCount = s.Comments.SelectMany(c => c.Replies).Count(),
});





share|improve this answer

































    0














    Unless I'm missing something, all the scores you're calculating with a separate method can instead be written as a public read-only (calculated) property of the Story class. The reply count can be obtained by using SelectMany (which is used to flatten lists of lists into a single list) and then getting the Count property:



    public class Story
    {
    public List<Comment> Comments { get; set; }
    public int InsightFulVoteCount { get; set; }
    public int UsefulVoteCount { get; set; }
    public int ViewCount { get; set; }

    public int PopularityScore
    {
    get
    {
    return
    (Comments?.Count ?? 0) * 4 +
    (Comments?.SelectMany(comment => comment.Replies).Count() ?? 0) * 4 +
    InsightFulVoteCount * 3 +
    UsefulVoteCount * 2 +
    ViewCount;
    }
    }
    }

    public class Comment
    {
    public List<string> Replies { get; set; }
    }




    In case you're not familiar with the null-conditional operator (?.), it returns null if the left operand (the object) is null before accessing the right operand (property or method of the object). If the left side is not null, then the property/method value is returned.



    Then the null-coalescing operator (??) evaluates the left operand (which is the result of the property or method access) and, if it's null, it returns the right operand ('0' in our case).



    Basically this simplifies the code. You don't have to do:



    var score = 0;
    if (Comments != null) score = Comments.Count;


    You can just do:



    var score = Comments?.Count ?? 0;





    share|improve this answer


























    • Thanks. I'm less concerned with the method which revolves around a single story than the method which accepts a list of stories and has to rank them.

      – J.G.Sable
      Nov 15 '18 at 1:01











    • Well after the above you can just do var rankedStories = stories.OrderByDescending(story => story.PopularityScore);

      – Rufus L
      Nov 15 '18 at 2:07













    • OrderByDescending puts the highest rank first. Technically you should be able to use your existing method, too...I just think a property is more readable. To use your existing method you would just do var ranked = stories.OrderByDescending(s => s.CalculateStoryPopularityScore());, but you'd want to get rid of the exception throwing part and just return zero instead.

      – Rufus L
      Nov 15 '18 at 3:43













    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53309872%2fmost-efficient-way-to-loop-through-two-c-sharp-lists%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    0














    Use SelectMany



    var commentCount = story.Comments.Count();

    // count all replies to all comments for a story
    var replyCountSum = story.Comments
    .SelectMany(c => c.Replies)
    .Count();


    Apply to a collection of stories:



    stories.Select(s => new
    {
    Story = s,
    CommentCount = s.Comments.Count(),
    ReplyCount = s.Comments.SelectMany(c => c.Replies).Count(),
    });





    share|improve this answer






























      0














      Use SelectMany



      var commentCount = story.Comments.Count();

      // count all replies to all comments for a story
      var replyCountSum = story.Comments
      .SelectMany(c => c.Replies)
      .Count();


      Apply to a collection of stories:



      stories.Select(s => new
      {
      Story = s,
      CommentCount = s.Comments.Count(),
      ReplyCount = s.Comments.SelectMany(c => c.Replies).Count(),
      });





      share|improve this answer




























        0












        0








        0







        Use SelectMany



        var commentCount = story.Comments.Count();

        // count all replies to all comments for a story
        var replyCountSum = story.Comments
        .SelectMany(c => c.Replies)
        .Count();


        Apply to a collection of stories:



        stories.Select(s => new
        {
        Story = s,
        CommentCount = s.Comments.Count(),
        ReplyCount = s.Comments.SelectMany(c => c.Replies).Count(),
        });





        share|improve this answer















        Use SelectMany



        var commentCount = story.Comments.Count();

        // count all replies to all comments for a story
        var replyCountSum = story.Comments
        .SelectMany(c => c.Replies)
        .Count();


        Apply to a collection of stories:



        stories.Select(s => new
        {
        Story = s,
        CommentCount = s.Comments.Count(),
        ReplyCount = s.Comments.SelectMany(c => c.Replies).Count(),
        });






        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Nov 14 '18 at 23:18

























        answered Nov 14 '18 at 23:12









        MohoMoho

        11.1k11723




        11.1k11723

























            0














            Unless I'm missing something, all the scores you're calculating with a separate method can instead be written as a public read-only (calculated) property of the Story class. The reply count can be obtained by using SelectMany (which is used to flatten lists of lists into a single list) and then getting the Count property:



            public class Story
            {
            public List<Comment> Comments { get; set; }
            public int InsightFulVoteCount { get; set; }
            public int UsefulVoteCount { get; set; }
            public int ViewCount { get; set; }

            public int PopularityScore
            {
            get
            {
            return
            (Comments?.Count ?? 0) * 4 +
            (Comments?.SelectMany(comment => comment.Replies).Count() ?? 0) * 4 +
            InsightFulVoteCount * 3 +
            UsefulVoteCount * 2 +
            ViewCount;
            }
            }
            }

            public class Comment
            {
            public List<string> Replies { get; set; }
            }




            In case you're not familiar with the null-conditional operator (?.), it returns null if the left operand (the object) is null before accessing the right operand (property or method of the object). If the left side is not null, then the property/method value is returned.



            Then the null-coalescing operator (??) evaluates the left operand (which is the result of the property or method access) and, if it's null, it returns the right operand ('0' in our case).



            Basically this simplifies the code. You don't have to do:



            var score = 0;
            if (Comments != null) score = Comments.Count;


            You can just do:



            var score = Comments?.Count ?? 0;





            share|improve this answer


























            • Thanks. I'm less concerned with the method which revolves around a single story than the method which accepts a list of stories and has to rank them.

              – J.G.Sable
              Nov 15 '18 at 1:01











            • Well after the above you can just do var rankedStories = stories.OrderByDescending(story => story.PopularityScore);

              – Rufus L
              Nov 15 '18 at 2:07













            • OrderByDescending puts the highest rank first. Technically you should be able to use your existing method, too...I just think a property is more readable. To use your existing method you would just do var ranked = stories.OrderByDescending(s => s.CalculateStoryPopularityScore());, but you'd want to get rid of the exception throwing part and just return zero instead.

              – Rufus L
              Nov 15 '18 at 3:43


















            0














            Unless I'm missing something, all the scores you're calculating with a separate method can instead be written as a public read-only (calculated) property of the Story class. The reply count can be obtained by using SelectMany (which is used to flatten lists of lists into a single list) and then getting the Count property:



            public class Story
            {
            public List<Comment> Comments { get; set; }
            public int InsightFulVoteCount { get; set; }
            public int UsefulVoteCount { get; set; }
            public int ViewCount { get; set; }

            public int PopularityScore
            {
            get
            {
            return
            (Comments?.Count ?? 0) * 4 +
            (Comments?.SelectMany(comment => comment.Replies).Count() ?? 0) * 4 +
            InsightFulVoteCount * 3 +
            UsefulVoteCount * 2 +
            ViewCount;
            }
            }
            }

            public class Comment
            {
            public List<string> Replies { get; set; }
            }




            In case you're not familiar with the null-conditional operator (?.), it returns null if the left operand (the object) is null before accessing the right operand (property or method of the object). If the left side is not null, then the property/method value is returned.



            Then the null-coalescing operator (??) evaluates the left operand (which is the result of the property or method access) and, if it's null, it returns the right operand ('0' in our case).



            Basically this simplifies the code. You don't have to do:



            var score = 0;
            if (Comments != null) score = Comments.Count;


            You can just do:



            var score = Comments?.Count ?? 0;





            share|improve this answer


























            • Thanks. I'm less concerned with the method which revolves around a single story than the method which accepts a list of stories and has to rank them.

              – J.G.Sable
              Nov 15 '18 at 1:01











            • Well after the above you can just do var rankedStories = stories.OrderByDescending(story => story.PopularityScore);

              – Rufus L
              Nov 15 '18 at 2:07













            • OrderByDescending puts the highest rank first. Technically you should be able to use your existing method, too...I just think a property is more readable. To use your existing method you would just do var ranked = stories.OrderByDescending(s => s.CalculateStoryPopularityScore());, but you'd want to get rid of the exception throwing part and just return zero instead.

              – Rufus L
              Nov 15 '18 at 3:43
















            0












            0








            0







            Unless I'm missing something, all the scores you're calculating with a separate method can instead be written as a public read-only (calculated) property of the Story class. The reply count can be obtained by using SelectMany (which is used to flatten lists of lists into a single list) and then getting the Count property:



            public class Story
            {
            public List<Comment> Comments { get; set; }
            public int InsightFulVoteCount { get; set; }
            public int UsefulVoteCount { get; set; }
            public int ViewCount { get; set; }

            public int PopularityScore
            {
            get
            {
            return
            (Comments?.Count ?? 0) * 4 +
            (Comments?.SelectMany(comment => comment.Replies).Count() ?? 0) * 4 +
            InsightFulVoteCount * 3 +
            UsefulVoteCount * 2 +
            ViewCount;
            }
            }
            }

            public class Comment
            {
            public List<string> Replies { get; set; }
            }




            In case you're not familiar with the null-conditional operator (?.), it returns null if the left operand (the object) is null before accessing the right operand (property or method of the object). If the left side is not null, then the property/method value is returned.



            Then the null-coalescing operator (??) evaluates the left operand (which is the result of the property or method access) and, if it's null, it returns the right operand ('0' in our case).



            Basically this simplifies the code. You don't have to do:



            var score = 0;
            if (Comments != null) score = Comments.Count;


            You can just do:



            var score = Comments?.Count ?? 0;





            share|improve this answer















            Unless I'm missing something, all the scores you're calculating with a separate method can instead be written as a public read-only (calculated) property of the Story class. The reply count can be obtained by using SelectMany (which is used to flatten lists of lists into a single list) and then getting the Count property:



            public class Story
            {
            public List<Comment> Comments { get; set; }
            public int InsightFulVoteCount { get; set; }
            public int UsefulVoteCount { get; set; }
            public int ViewCount { get; set; }

            public int PopularityScore
            {
            get
            {
            return
            (Comments?.Count ?? 0) * 4 +
            (Comments?.SelectMany(comment => comment.Replies).Count() ?? 0) * 4 +
            InsightFulVoteCount * 3 +
            UsefulVoteCount * 2 +
            ViewCount;
            }
            }
            }

            public class Comment
            {
            public List<string> Replies { get; set; }
            }




            In case you're not familiar with the null-conditional operator (?.), it returns null if the left operand (the object) is null before accessing the right operand (property or method of the object). If the left side is not null, then the property/method value is returned.



            Then the null-coalescing operator (??) evaluates the left operand (which is the result of the property or method access) and, if it's null, it returns the right operand ('0' in our case).



            Basically this simplifies the code. You don't have to do:



            var score = 0;
            if (Comments != null) score = Comments.Count;


            You can just do:



            var score = Comments?.Count ?? 0;






            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Nov 15 '18 at 3:48

























            answered Nov 15 '18 at 0:40









            Rufus LRufus L

            18.6k31631




            18.6k31631













            • Thanks. I'm less concerned with the method which revolves around a single story than the method which accepts a list of stories and has to rank them.

              – J.G.Sable
              Nov 15 '18 at 1:01











            • Well after the above you can just do var rankedStories = stories.OrderByDescending(story => story.PopularityScore);

              – Rufus L
              Nov 15 '18 at 2:07













            • OrderByDescending puts the highest rank first. Technically you should be able to use your existing method, too...I just think a property is more readable. To use your existing method you would just do var ranked = stories.OrderByDescending(s => s.CalculateStoryPopularityScore());, but you'd want to get rid of the exception throwing part and just return zero instead.

              – Rufus L
              Nov 15 '18 at 3:43





















            • Thanks. I'm less concerned with the method which revolves around a single story than the method which accepts a list of stories and has to rank them.

              – J.G.Sable
              Nov 15 '18 at 1:01











            • Well after the above you can just do var rankedStories = stories.OrderByDescending(story => story.PopularityScore);

              – Rufus L
              Nov 15 '18 at 2:07













            • OrderByDescending puts the highest rank first. Technically you should be able to use your existing method, too...I just think a property is more readable. To use your existing method you would just do var ranked = stories.OrderByDescending(s => s.CalculateStoryPopularityScore());, but you'd want to get rid of the exception throwing part and just return zero instead.

              – Rufus L
              Nov 15 '18 at 3:43



















            Thanks. I'm less concerned with the method which revolves around a single story than the method which accepts a list of stories and has to rank them.

            – J.G.Sable
            Nov 15 '18 at 1:01





            Thanks. I'm less concerned with the method which revolves around a single story than the method which accepts a list of stories and has to rank them.

            – J.G.Sable
            Nov 15 '18 at 1:01













            Well after the above you can just do var rankedStories = stories.OrderByDescending(story => story.PopularityScore);

            – Rufus L
            Nov 15 '18 at 2:07







            Well after the above you can just do var rankedStories = stories.OrderByDescending(story => story.PopularityScore);

            – Rufus L
            Nov 15 '18 at 2:07















            OrderByDescending puts the highest rank first. Technically you should be able to use your existing method, too...I just think a property is more readable. To use your existing method you would just do var ranked = stories.OrderByDescending(s => s.CalculateStoryPopularityScore());, but you'd want to get rid of the exception throwing part and just return zero instead.

            – Rufus L
            Nov 15 '18 at 3:43







            OrderByDescending puts the highest rank first. Technically you should be able to use your existing method, too...I just think a property is more readable. To use your existing method you would just do var ranked = stories.OrderByDescending(s => s.CalculateStoryPopularityScore());, but you'd want to get rid of the exception throwing part and just return zero instead.

            – Rufus L
            Nov 15 '18 at 3:43




















            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53309872%2fmost-efficient-way-to-loop-through-two-c-sharp-lists%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Florida Star v. B. J. F.

            Danny Elfman

            Lugert, Oklahoma