'Remove every nth item from a list in C#

New to C#, as a beginner program I would like to recreate the MASH game as a console application. If you don't know, this is the MASH game: https://mashapp.com/play-mash-online-free/

I currently have the code in place to receive user input and put the data into separate lists.

In my version of the game, the program takes your name and counts how many characters are in it (numberOfLetters). This is an alternative to drawing a spiral like in the link above. It would then use this value to remove every nth value until there is only one of each item in each list.

I am struggling to write the logic for this last section. I think it would make sense to create a cumulative list and then remove the nth terms, but I am not sure how to tell the program how to leave one item per list.

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Welcome to the MASH game!");

        Console.WriteLine("Enter three colleges or universities...");
        List<string> CollegeList = new List<string>();
        for (int i = 0; i < 3; i++)
        {
            CollegeList.Add(Console.ReadLine());
        }


        Console.WriteLine("Enter three babes or dudes that you might marry...");
        List<string> BabeList = new List<string>();
        for (int i = 0; i < 3; i++)
        {
            BabeList.Add(Console.ReadLine());
        }

        Console.WriteLine("Enter three (3) cities which you might live in...");
        List<string> CityList = new List<string>();
        for (int i = 0; i < 3; i++)
        {
            CityList.Add(Console.ReadLine());
        }

        Console.WriteLine("Enter three numbers...");
        List<string> NumberList = new List<string>();
        for (int i = 0; i < 3; i++)
        {
            NumberList.Add(Console.ReadLine());
        }

        Console.WriteLine("Enter three majors...");
        List<string> MajorList = new List<string>();
        for (int i = 0; i < 3; i++)
        {
            MajorList.Add(Console.ReadLine());
        }

        Console.WriteLine("Enter three occupations...");
        List<string> JobList = new List<string>();
        for (int i = 0; i < 3; i++)
        {
            JobList.Add(Console.ReadLine());
        }

        List<string> ShelterList = new List<string>();
        ShelterList.Add("Mansion");
        ShelterList.Add("Apartment");
        ShelterList.Add("Shack");
        ShelterList.Add("House");

        Console.WriteLine("Alright smartass, enter your name");
        string Name = Console.ReadLine();
        int numberOfLetters = Name.ToCharArray().Count();
        Console.WriteLine("........." + numberOfLetters + ".........");


       


    }
}}

Any recommendations for how to approach this?



Solution 1:[1]

Well, let's state the problem an then solve it. Having a list, say

{0, 1, 2, 3, 4, 5, 6, 7, 8}

we want to remove every item startAt from some index, e.g.

{0, 1, 2, 3, 4, 5, 6, 7, 8} => {0, 1, 2, 3, 5, 7}
          ^  *     *     *      
          |  remove every 2nd item
          |  
          start at 4th item     
   

Code:

// return true if at least one item has been removed
public static bool Remover<T>(List<T> list, int every, int startAt = 0) {
  if (list == null)
    throw new ArgumentNullException(nameof(list));
  if (every <= 0)
    throw new ArgumentOutOfRangeException(nameof(every));

  if (startAt >= list.Count)
    return false;

  int shift = 0;

  for (int i = Math.Max(0, startAt); i < list.Count; ++i) 
    if ((i - startAt) % every == 0)
      shift += 1;
    else
      list[i - shift] = list[i];
  
  list.RemoveRange(list.Count - shift, shift);

  return shift > 0;
}

Solution 2:[2]

I am struggling to write the logic for this last section. I think it would make sense to create a cumulative list and then remove the nth terms, but I am not sure how to tell the program how to leave one item per list.

This highly depends on your integer numberOfLetters. Factors such as if this is greater than the size of the list before and after iteration.

Console.WriteLine("Alright smartass, enter your name");
string Name = Console.ReadLine();
int numberOfLetters = Name.Length;
int len = list.Count;
for(int i=0; i<len; i++) {
   if(numberOfLetters < len && i % numberOfLetters == 0 && len > 1) {
   list.RemoveAt(i);
  }
}

The above logic cannot gurantee that the list will be reduced to 1 item. If you need this to be down to one last item then you will need to use the random() like this especially if the list size is lesser than the numberOfLetters integer.

Console.WriteLine("Alright smartass, enter your name");
string Name = Console.ReadLine();
int numberOfLetters = Name.Length;
int len = list.Count;
var rdm = new Random();
for(int i=0; i<len; i++) {
   // ignoring the nth item
   if(len > 1) {
   list.RemoveAt(rdm.Next(0, len));
  }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Dmitry Bychenko
Solution 2