Reputation: 3
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
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
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
Reputation: 3141
There are ways to do it.
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)
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