Question

Currently the method uses a for() loop and a foreach() loop to iterate through each array element in the list to compare a value inside the array elements. I require the for loop to record the current index value of the list if the criteria is met so that I know where to rebuild the list afterwards.

// update high score list
public void updateScores()
{
    // if the list of scores isnt empty compare score
    if (list.Count() != 0)
    {
        // loop through each array in the list
        for (int i = 0; i <= list.Count(); i++)
        {
            // look into each linedata array in the list
            foreach (string[] ld in list)
            {
                // only look at scores that are the same difficulty
                if (lineData[1] == difficulty)
                {
                    // if score is greater than this score in list
                    if (score > Convert.ToInt32(lineData[0]))
                    {
                        // record which index the score was higher than
                        scoreIndex = i;
                    }
                }
            }
        }

        // if the score is higher than one of the saved highscores remove all lower score down one index
        for (int i = list.Count() - 1; i > scoreIndex; i--)
        {
            // continue
        }
    }
}

This is how the list is built:

// load highscores
public bool LoadScores()
{
    // attempt to load the highscore list
    if (File.Exists("highScores"))
    {
        // loop through each line in the file
        while ((line = file.ReadLine()) != null)
        {
            // seperate the score from the difficulty
            lineData = line.Split(',');

            // add each line to the list
            list.Add(lineData);
        }
        return true;
    }
    else{return false;}
}

highscores text file:

1231,1
1231232,2
4664,2
252,1
475532,1

Question: Is there a better way of keeping track of the list index whilst iterating through a list.

Edit: Basically I am comparing a players score with a list of highscores. If the score is high enough lower scores will be moved down to allow the new score into the list

Was it helpful?

Solution 2

Preamble :)

Have you ever tried to execute your code? :)

  1. You have a bug: outer loop will run out of list bounds.
  2. Checking for list size before iterating through it is usually unnecessary.
  3. I don't see any code to sort list before executing updateScores. Your code will provide unexpected results on unsorted lists.
  4. You are using strings now. Sorting array of strings is definitely not what you want. Consider using structs with integers for high scores values.

Answering your question

  1. You can just start inner loop from outer loop and use break statement. See example:

    public void updateScores()
    {
        // loop through each array in the list
        for (int i = 0; i < list.Count(); i++)
        {
            string[] lineData = list[i];
            if (lineData[1] == difficulty)
            {
                if (score > Convert.ToInt32(lineData[0]))
                {
                    // if the score is higher than one of the saved highscores remove all lower score down one index
                    for (int j = list.Count() - 1; j > scoreIndex; j--)
                    {
                        // continue
                    }
                    break;
                }
            }
        }
    }
    
  2. Negating conditions can simplify the code:

    public void updateScores()
    {
        // loop through each array in the list
        for (int i = 0; i < list.Count(); i++)
        {
            string[] lineData = list[i];
            if (lineData[1] != difficulty)
                continue;
            if (score <= Convert.ToInt32(lineData[0]))
                continue;
            // if the score is higher than one of the saved highscores remove all lower score down one index
            for (int j = list.Count() - 1; j > scoreIndex; j--)
            {
                // continue
            }
            break;
        }
    }
    

OTHER TIPS

First of all, Sergey is correct; this code is a mass of bugs and bad practices. Two that Sergey did not mention are:

  • The standard in C# is to PascalCase your method names, not camelCase them.
  • Don't call the extension method Count() on an IList. Use the Count property.

I would recommend that you get in the habit of writing smaller methods that call each other, and then carefully test each one.

As some commenters noted, you can solve this problem more easily by maintaining a sorted list, taking the union of the old list and the new item, sorting that sequence, truncating it to include only the top n, turning that back into a list, and you're done.

None of that answers your question, which was

Is there a better way of keeping track of the list index whilst iterating through a list?

I submit to you that this is not quite the right question to ask. A better question is:

How can I determine the index of the first item in a list which matches a given condition?

Make an extension method in a static class:

    public static int? FirstIndex<T>(this IEnumerable<T> items, Func<T, bool> predicate) 
    {
      if (items == null) 
        throw new ArgumentNullException("items");
      if (predicate == null) 
        throw new ArgumentNullException("predicate");
      int index = 0;
      foreach (var item in items) 
      {
        if (predicate(item))
          return index;
        index += 1;
      }
      return null;
    }

This extension method takes a sequence and a predicate and returns the index of the first item that matches the predicate, or null if no item matches the predicate. Note that this works on any sequence, not just an IList -- the [] indexer and Count property are not used.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top