Catchybatchy
Catchybatchy

Reputation: 3

Get an certain number of lines from a txt file in a list.

I have a problem. I'm making a tennis tournament program for a school project. We're supposed to use txt files, where they're being read an we need to be able to extract an certain amount of players, that is going to be used for simulation of the tournament.

public class ReadPlayers
{
    private List<ReadFiles> players = new List<ReadFiles>(); //Opretter en liste af strenge. 
    public string FileName { get; set; }
    public string Delimiter { get; set; }
    public ReadPlayers(string fn, string delim = "|") //Konstruktur
    {
        FileName = fn;
        Delimiter = delim;
    }

    public override string ToString()
    {
       var rv = "";

       foreach (var c in players)
             rv += c + "\n";
         return rv;
    }

    public void Load()
    {
        TextFieldParser par = new TextFieldParser(FileName, Encoding.GetEncoding("iso-8859-1"));
        par.TextFieldType = FieldType.Delimited;
        par.SetDelimiters(Delimiter);
        while (!par.EndOfData)
        {
            string[] fields = par.ReadFields();
            string FirstName = fields[1];
            string MiddleName = fields[2];
            string LastName = fields[3];
            DateTime DateOfBirth = DateTime.ParseExact(fields[4], "yyyy-MM-dd", CultureInfo.InvariantCulture);
            String Country = fields[5];
            string ShortNameCountry = fields[6];
            var c = new ReadFiles(FirstName, MiddleName, LastName, DateOfBirth, Country, ShortNameCountry);
            players.Add(c);
        }
        players.Shuffle();
        par.Close();

And in my main I load the file and print it. That works perfectly. But I need to be able to print only 8, 16, 32 or 64 players from the list.

Upvotes: 0

Views: 80

Answers (3)

Matthew Watson
Matthew Watson

Reputation: 109567

You can use what's known as "Reservoir sampling" to select a specified number of items from a sequence of unknown length (but which must be long enough to supply all the items).

The algorithm looks like this:

public static T[] RandomlySelectedItems<T>(IEnumerable<T> items, int n, Random rng)
{
    var result = new T[n];
    int index = 0;
    int count = 0;

    foreach (var item in items)
    {
        if (index < n)
        {
            result[count++] = item;
        }
        else
        {
            int r = rng.Next(0, index + 1);

            if (r < n)
                result[r] = item;
        }

        ++index;
    }

    if (index < n)
        throw new ArgumentException("Input sequence too short");

    return result;
}

Note that the resulting array is in a random order; it does not contain elements in the order that they appeared in the input sequence.

You can use it to select N lines at random (and in a random order) from a text file as follows:

string filename = "Your filename goes here";
var lines = File.ReadLines(filename);
int n = 16; // Number of lines to select.
var result = RandomlySelectedItems(lines, n, new Random()).ToList();

Upvotes: 1

Steve
Steve

Reputation: 216293

You can change your ToString() method to receive two parameters
The first one is the number of players you want to return in the string, the second parameter is the number of players to skip from the list before getting the next batch of players.

public string ToString(int takeCount, int skipFirst)
{
   return string.Join(Environment.NewLine, players.Skip(skipFirst).Take(takeCount));
}

Add also a property that tells you how many players are in the list

public int NumberOfPlayers
{
   get { return players.Count; }
}

in this way you can call the ToString inside a loop and receive batches of players until you reach the total number of players present in the list

int batchSize = 16;
for(int i = 0; i < readPlayerInstance.NumberOfPlayers; i+=batchSize)
{
    string players = readPlayerInstance.ToString(batchSize, i)
    .... show your players in batch of 16
}

Of course, instead of changing the override of the ToString() method you simply add your own method that returns the players in batches in the way you like and (for example) return a sublist of your players.

public List<ReadFiles> GetPlayers(int takeCount, int skipFirst)
{
   return players.Skip(skipFirst).Take(takeCount).ToList();
}

Upvotes: 0

Mukul Varshney
Mukul Varshney

Reputation: 3141

There are ways to do it.

  1. Declare a constant(MAX_PLAYERS) or a variable to store the Max_Count of players you want i.e. 8, 16, 32 or 64. Declare a counter and increment it in the while loop. Once counter is reached exit from the loop. Here you will get only 1st 8 or 16 players form file which you are interested in. Not required to read full file when all records are not interested.

while (!par.EndOfData && counter < MAX_PLAYERS)

  1. You have used the statement players.Shuffle();. So just pick the top MAX_PLAYERS from the list after shuffling. This makes more logical as you retain the full list of players and also the selected list out of them.

var selectedList = players.Take(MAX_PLAYERS);

Upvotes: 0

Related Questions