【问题标题】:Splitting data from a text file into parallel arrays将文本文件中的数据拆分为并行数组
【发布时间】:2013-04-07 08:58:18
【问题描述】:

我的教授给全班举了一个 C# 的例子,可以用来从文本文件中分割数据。我正在尝试将它用于涉及拆分 txt 内容的项目。文件分成 4 个数组或字段。代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

class Program
{
    static void Main()
    {
        int i = 0;
        foreach (string line in File.ReadAllLines("census.txt"))
        {
            string[] parts = line.Split(',');
            foreach (string part in parts)
            {
                Console.WriteLine("{0}",

                    part);
            }
            i++; 
        }
    }
}

这里是 census.txt

21,f, s, 14

41,f, m, 22

12, m, s, 12

11, f, s, 8

29, m, m, 4

6, m, s, 12

9, f, s, 2

30, f, s, 1

这应该是按年龄、性别、婚姻状况和地区划分的假设人口普查数据。我不断得到的输出是单行中的每个数字或字符,如下所示:

21

f

s

14

41

f

m

22

等等。

我认为这意味着它正在工作,但我想知道如何使用它来输入 4 个并行数组。我还想了解更多关于将其拆分为 4 个字段、结构或类的信息。项目的下一部分涉及每次出现某个年龄编号或地区编号时进行计数,这将涉及大量数组。

【问题讨论】:

标签: c# arrays file struct split


【解决方案1】:

我会稍微扩展一下irsog的回答:

  • 使用类而不是结构
  • 使用属性而不是字段
  • 使用GenderMaritalStatus 枚举代替纯字符串

代码:

public class Person
{
    public int Age { get; set; }
    public MaritalStatus MaritalStatus { get; set; }
    public Gender Gender { get; set; }
    public int District { get; set; }
}

public enum MaritalStatus
{
    Single, Married
}

public enum Gender
{
    Male, Female
}

及用法:

var people = new List<Person>();

foreach (string line in File.ReadAllLines("Input.txt"))
{
    string[] parts = line.Split(',');

    people.Add(new Person()  {
        Age = int.Parse(parts[0]),
        MaritalStatus = parts[1] == "s" ? MaritalStatus.Single : MaritalStatus.Married,
        Gender = parts[2] == "m" ? Gender.Male : Gender.Female,
        District = int.Parse(parts[3])
    });
}

【讨论】:

    【解决方案2】:

    这是旧线程,但正如谷歌在前几页中显示的那样,我决定发送我的评论。我强烈建议不要使用给定的 txt 文件格式,因为它不能防错。如果 census.txt 不能保证是理想的,特别是如果它应该由某个第三方(用户、管理员、任何人)创建,那么我强烈建议记录以一些符号结尾,如下所示: 21,f,s,14;

    41,f,m,22; 然后我们要做的第一件事 - 我们得到记录数组,如下所示:

    string[] 行 = text.split(';');

    然后简单地再次拆分 - 这次是为了获取记录元素。

    foreach(以行为单位的字符串记录)

    {

    string[] fields = record.split(',');

    }

    这样不仅更容易读取记录/字段,还可以轻松检查文件的一致性、忽略错误(空记录)、检查每条记录中的字段数等。

    【讨论】:

      【解决方案3】:

      通用列表(在此处的其他 2 个当前答案中使用)是最好的方法。但是,如果您需要将数据保存在数组中(正如您之前的 question 似乎表明的那样),那么您可以像这样修改教授的代码:

      C#

      int[] districtDataD = new int[900];
      string[] districtDataG = new string[900];
      string[] districtDataM = new string[900];
      int[] districtDataA = new int[900];
      
      int i = 0;
      foreach (string line in File.ReadAllLines("census.txt"))
      {
          string[] parts = line.Split(',');
      
          districtDataD[i] = int.Parse(parts[0]);
          districtDataS[i] = parts[1];
          districtDataM[i] = parts[2];
          districtDataA[i] = int.Parse(parts[3]);
          i++;
      }
      

      VB.NET(因为您最初的问题是用 VB.NET 标记的):

      Dim districtDataD() As New Integer(900)
      Dim districtDataS() As New String(900)
      Dim distrcitDataM() As New String(900)
      Dim districtDataA() As New Integer(900)
      
      Dim i As Integer = 0
      
      For Each Dim line As String In File.ReadAllLines("census.txt")
          Dim string() As parts = line.Split(',')
      
          districtDataD(i) = Integer.Parse(parts(0))
          districtDataS(i) = parts(1)
          districtDataM(i) = parts(2)
          districtDataA(i) = Integer.Parse(parts(3))
      
          i++
      Next
      

      您也可以使用 structclass 并拥有一个包含该对象的数组,但看起来您是教授希望您使用 4 个单独的数组。如果你可以使用一个,你可以像这样简单地声明数组,例如:

      C#

      Person[] districtData = new Person[900];
      

      VB.NET

      Dim districtData() As New Person(900)
      

      然后您可以在拆分逻辑中执行此操作(请注意,如果您的对象中的 Distric 和 Age 是整数,您将必须转换或解析它们,如下所示):

      C#

      districtData[i] = new Person() { District = int.Parse(parts[0]), Gender = parts[1], MaritalStatus = parts[2], Age = int.Parse(parts[3]) };
      

      VB.NET

      districtData[i] = new Person() With { .District = Integer.Parse(parts[0]), .Gender = parts[1], .MaritalStatus = parts[2], .Age = Integer.Parse(parts[3]) }
      

      此代码存在风险,如果您有超过 900 行数据,您将获得索引超出范围异常。避免这种情况的一种方法是使用 while 循环修改我上面放置的代码,该循环检查目标数组的边界或未超过的行数,如下所示:

      C#

      string[] lines = File.ReadAllLines("census.txt");
      int i = 0;
      
      while (i < 900 && i < parts.Length)
      {
      
          // split logic goes here
      }
      

      VB.NET

      Dim lines As String() = File.ReadAllLines("census.txt")
      Dim i As Integer = 0
      
      While (i < 900 AndAlso i < lines.Length)
      
          ' split logic goes here
      End While
      

      我还没有测试过代码,但是如果您必须使用数组,希望这会对您有所帮助。

      【讨论】:

      • 谢谢!我回头看,我不必使用并行数组,但我不知道如何将结构放入伪代码或流程图中,所以我想我会坚持使用数组。如果我确实使用了类,我是否应该放置一个循环来计算 char 或 int 在类或主程序中出现的次数? C# 中的顶部也给了我一个“不能隐式地将 string[] 转换为 int[]”的错误。Split 的东西。
      • 糟糕..我的错。我已经编辑了代码,因此数组是正确的(int 或 string,取决于),并且文件中的文本被转换为 int(在必要时)。
      • 我会将计算字符或整数出现次数的方法放在主程序中。主程序是您创建类集合的地方 - 各个类本身不知道令牌在集合中出现了多少次。
      【解决方案4】:

      您可以为所需信息制作结构:

      public struct Info
      {
          public int Age;
          public string gender;
          public string status;
          public int district;
      }
      

      并将数据插入到您的结构列表中:

        List<Info> info = new List<Info>();
          foreach (string line in File.ReadAllLines("census.txt"))
          {
              string[] parts = line.Split(',');
      
                  info.Add(new Info() {Age=int.Parse(parts[0]), gender=parts[1], status=parts[2], district=int.Parse(parts[3]) });
          }
      

      现在你有了个人信息列表。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-07-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-06-11
        相关资源
        最近更新 更多