【问题标题】:Using a for loop to iterate from an array to a list使用 for 循环从数组迭代到列表
【发布时间】:2017-12-18 12:46:53
【问题描述】:

我有一个文本文件,它被分成许多部分,每个部分大约 10 行左右。我正在使用 File.ReadAllLines 将文件读入一个数组,数组的每个元素一行,然后我试图解析文件的每个部分以仅带回一些数据。我将结果存储在一个列表中,并希望最终将列表导出到 csv。

我的 for 循环给我带来了麻烦,因为它循环了正确的次数,但每次只从文本文件的第一部分提取数据,而不是从第一部分提取数据然后继续从下一节中提取数据。我确定我在 for 循环或每个循环中都做错了什么。任何帮助我解决这个问题的线索将不胜感激!谢谢 大卫

到目前为止我的代码:

namespace ParseAndExport
{
    class Program
    {

        static readonly string sourcefile = @"Path";

        static void Main(string[] args)
        {
            string[] readInLines = File.ReadAllLines(sourcefile);
            int counter = 0;
            int holderCPStart = counter + 3;//Changed Paths will be an different number of lines each time, but will always start 3 lines after the startDiv

            /*Need to find the start of the section and the end of the section and parse the bit in between.
             * Also need to identify the blank line that occurs in each section as it is essentially a divider too.*/
            int startDiv = Array.FindIndex(readInLines, counter, hyphens72);
            int blankLine = Array.FindIndex(readInLines, startDiv, emptyElement);
            int endDiv = Array.FindIndex(readInLines, counter + 1, hyphens72);

            List<string> results = new List<string>();

            //Test to see if FindIndexes work. Results should be 0, 7, 9 for 1st section of sourcefile
            /*Console.WriteLine(startDiv);
            Console.WriteLine(blankLine);
            Console.WriteLine(endDiv);*/

            //Check how long the file is so that for testing we know how long the while loop should run for
            //Console.WriteLine(readInLines.Length); 
            //sourcefile has 5255 lines (elements) in the array


           for (int i = 0; i <= readInLines.Length; i++)
            {

                if (i == startDiv)
                {

                    results = (readInLines[i + 1].Split('|').Select(p => p.Trim()).ToList());
                    string holderCP = string.Join(Environment.NewLine, readInLines, holderCPStart, (blankLine - holderCPStart - 1)).Trim();
                    results.Add(holderCP);
                    string comment = string.Join(" ", readInLines, blankLine + 1, (endDiv - (blankLine + 1)));//in case the comment is more than one line long
                    results.Add(comment);

                    i = i + 1;
                }
                else
                {
                    i = i + 1;
                }


                foreach (string result in results)
                {


                    Console.WriteLine(result);
                }



                //csvcontent.AppendLine("Revision Number, Author, Date, Time, Count of Lines, Changed Paths, Comments");

                /* foreach (string result in results)
                 {

                     for (int x = 0; x <= results.Count(); x++)
                     {

                         StringBuilder csvcontent = new StringBuilder();
                         csvcontent.AppendLine(results[x] + "," + results[x + 1] + "," + results[x + 2] + "," + results[x + 3] + "," + results[x + 4] + "," + results[x + 5]);
                         x = x + 6;
                         string csvpath = @"addressforcsvfile";
                         File.AppendAllText(csvpath, csvcontent.ToString());


                     }

                 }*/

            }

            Console.ReadKey();

        }







        private static bool hyphens72(String h)
        {
            if (h == "------------------------------------------------------------------------")
            {
                return true;
            }
            else
            {
                return false;
            }



        }

        private static bool emptyElement(String ee)
        {
            if (ee == "")
            {
                return true;
            }
            else
            {
                return false;
            }

        }




    }
}

【问题讨论】:

  • 每个部分是否以所有这些连字符开头和/或结尾? IMO 简化此操作的第一步是将 读取处理 分为两个不同的任务。也许创建一个字符串列表。每次遇到连字符时,开始一个新列表并用所有文本行填充它,直到到达下一个“------------------”。然后重复。完成后,您将获得一个列表列表,其中每个 lnner 列表是连字符之间的一大块行。现在拆分完成,您可以处理它们。但不要试图将它们拆分并以一种方法处理。

标签: c# for-loop foreach export-to-csv


【解决方案1】:

您似乎正试图抓取文件中所有非“------”的行并将它们放入字符串列表中。

你可以试试这个:

var lineswithoutdashes = readInLines.Where(x => x != hyphens72).Select(x => x).ToList();

现在您可以使用此列表并使用“|”进行拆分提取你想要的字段

【讨论】:

  • 谢谢凯文,非常感谢
【解决方案2】:

逻辑似乎是错误的。代码本身也存在问题。我不确定你到底想做什么。无论如何,我希望会有所帮助的一些提示:

  1. if (i == startDiv) 检查 I 是否等于 startDiv。我假设满足此条件时发生的逻辑就是您所说的“从第一部分中提取数据”。没错,因为您只在 I 等于 startDiv 时才运行此代码。

  2. 在 for 循环中增加计数器 I,这本身也会增加计数器 i。

  3. 如果 2. 中的问题不存在,那么我建议不要在 if (i == startDiv) 的真假条件下执行相同的操作“i = i + 1” .

假设我假设这个文件实际上可能很大,最好不要将它存储在内存中,而是逐行读取文件并逐行处理。目前没有明显的理由为什么要消耗这么多内存,除非是因为这个 API“File.ReadAllLines(sourcefile)”的便利性。我不会太害怕阅读这样的文件:

Try (BufferedReader br = new BufferedReader(new FileReader (file))) {
    String line;
    while ((line = br.readLine()) != null) {
      // process the line.
    }
}

您可以跳过这些行,直到您通过该行等于 hyphens72 的位置。

然后对于每一行,您使用您在 (i == startDiv) 的真实情况下提供的代码处理该行,或者至少,根据您的描述,这就是我假设您正在尝试做的事情。

【讨论】:

  • 感谢乔,这让我有了一些需要关注和解决的问题。非常感谢
  • 谢谢 Jo,我以前没有听说过 BufferedReader,但会查一下。非常感谢
【解决方案3】:

int startDiv 将返回包含hyphens72行号

因此,您当前的 for 循环只会复制到与计算的行号匹配的单行的结果。

我猜你想在当前行搜索startDiv的位置?

  const string hyphens72;
  // loop over lines
  for (var lineNumber = 0; lineNumber  <= readInLines.Length; lineNumber++) {
      string currentLine = readInLines[lineNumber];
      int startDiv = currentLine.IndexOf(hyphens72);
      // loop over characters in line
      for (var charIndex = 0; charIndex < currentLine.Length; charIndex++) {
          if (charIndex  == startDiv) {
              var currentCharacter = currentLine[charIndex];
              // write to result ...
          }
          else {
              continue; // skip this character
          }
      }
  }

【讨论】:

    【解决方案4】:

    有几件事可以改进。

    • 我会使用 ReadLines 而不是 File.ReadAllLines(,因为 ReadAllLines 会读取所有行。 ReadLines 将对其进行流式传输。

    • 使用results = (readInLines[i + 1].Split('|').Select(p =&gt; p.Trim()).ToList()); 行,您将覆盖之前的结果列表。您最好使用results.AddRange() 添加新结果。

    • for (int i = 0; i &lt;= readInLines.Length; i++) 表示当长度 = 10 时,它将执行 11 次迭代。 (1 太多)(删除=

    • Array.FindIndex(readInLines, counter, hyphens72); 将进行扫描。在大文件上,完全阅读它们并在其中搜索需要很长时间。 尝试仅触摸单行。

    我无法测试你在做什么,但这里有一个提示:

    IEnumerable<string> readInLines = File.ReadLines(sourcefile);
    
    bool started = false;
    
    List<string> results = new List<string>();
    
    foreach(var line in readInLines)
    {
        // skip empty lines
        if(emptyElement(line))
            continue;
    
        // when dashes are found, flip a boolean to activate the reading mode.
        if(hyphens72(line))
        {
            // flip state.. (start/end)
            started != started;
        }
    
        if(started)
        {
            // I don't know what you are doing here precisely, do what you gotta do. ;-)
            results.AddRange((line.Split('|').Select(p => p.Trim()).ToList()));
            string holderCP = string.Join(Environment.NewLine, readInLines, holderCPStart, (blankLine - holderCPStart - 1)).Trim();
            results.Add(holderCP);
            string comment = string.Join(" ", readInLines, blankLine + 1, (endDiv - (blankLine + 1)));//in case the comment is more than one line long
            results.Add(comment);
        }
    
    }
    
    foreach (string result in results)
    {
        Console.WriteLine(result);
    }
    

    【讨论】:

    • 谢谢 Jeroen,看来我需要重新思考我的逻辑了,但是很高兴能有意见让我指出一个更好的方向。非常感谢
    【解决方案5】:

    您可能想从这样的课程开始。我不知道每个部分是否以一排连字符开头,或者只是介于两者之间。这应该可以处理任何一种情况。

    这将要做的是获取您巨大的字符串列表(文件中的行)并将其分成块 - 每个块是一组行(根据您的 OP,大约 10 行。)

    原因是尝试读取文件、查找连字符并同时处理文件内容是不必要的复杂。相反,一个类接受输入并将其分成块。这就是它所做的一切。

    另一个类可能会读取文件并将其内容传递给该类以分解它们。然后输出是单独的文本块。

    然后另一个类可以处理 10 行左右的单个部分,而不必担心连字符或块与另一个块之间的分隔。

    现在这些类中的每一个都在做自己的事情,为它们分别编写单元测试会更容易。您可以测试您的“处理”类是否接收到 10 行左右的数组,并执行它应该对它们执行的任何操作。

    public class TextSectionsParser
    {
        private readonly string _delimiter;
    
        public TextSectionsParser(string delimiter)
        {
            _delimiter = delimiter;
        }
    
        public IEnumerable<IEnumerable<string>> ParseSections(IEnumerable<string> lines)
        {
            var result = new List<List<string>>();
            var currentList = new List<string>();
    
            foreach (var line in lines)
            {
                if (line == _delimiter)
                {
                    if(currentList.Any())
                        result.Add(currentList);
                    currentList = new List<string>();
                }
                else
                {
                    currentList.Add(line);
                }
            }
            if (currentList.Any() && !result.Contains(currentList))
            {
                result.Add(currentList);
            }
            return result;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-07-25
      • 1970-01-01
      • 1970-01-01
      • 2020-07-02
      • 1970-01-01
      • 1970-01-01
      • 2013-01-16
      相关资源
      最近更新 更多