从列表中的 txt 文件中获取一定数量的行。

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

我有问题。我正在为学校项目制作网球锦标赛程序。我们应该使用 txt 文件,在其中读取它们,我们需要能够提取一定数量的玩家,这将用于模拟锦标赛。

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();

在我的主程序中,我加载文件并打印它。这非常有效。但我只需要能够从列表中打印出 8、16、32 或 64 名球员。

有很多方法可以做到。

  1. 声明一个常量 (MAX_PLAYERS) 或一个变量来存储您想要的 Max_Count 个玩家,即 8、16、32 或 64。声明一个计数器并在 while 循环中递增它。一旦达到计数器就退出循环。在这里你只会得到你感兴趣的第一个 8 或 16 球员表格文件。当所有记录都不感兴趣时​​不需要阅读完整文件。

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

  1. 您使用了语句players.Shuffle();。因此,只需在洗牌后从列表中选择顶部 MAX_PLAYERS 即可。这更合乎逻辑,因为您保留了完整的玩家列表以及从中选择的列表。

var selectedList = players.Take(MAX_PLAYERS);

您可以更改 ToString() 方法以接收两个参数
第一个是你想要在字符串中 return 的玩家数量,第二个参数是在获得下一批玩家之前要从列表中跳过的玩家数量。

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

另外添加一个 属性,告诉您列表中有多少玩家

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

通过这种方式,您可以在循环中调用 ToString 并接收一批玩家,直到达到列表中存在的玩家总数

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
}

当然,您无需更改 ToString() 方法的重写,只需添加您自己的方法即可 return 以您喜欢的方式分批播放玩家并且(例如)return 你的玩家的子列表。

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

您可以使用所谓的 "Reservoir sampling" 来 select 来自未知长度序列的指定数量的项目(但必须足够长以提供所有项目)。

算法如下所示:

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;
}

请注意,生成的数组是随机排列的;它不包含元素在输入序列中出现的顺序。

您可以使用它从文本文件中随机 select N 行(并以随机顺序),如下所示:

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();