我正在研究一个程序,该程序从文件读取数据,将数据存储在列表中,然后以特殊格式将数据写入新文件。我创建了一种方法来读取原始文件并将其存储在列表中。
我从中读取的文件是数字列表。每行一个数字。
写入新文件的方法遇到问题。 我在处理50个项目并将它们写入一行,然后在接下来的50个项目并写入下一行时遇到问题。该方法是获取前50个项目并将其写入并在每行上重复这50个项目。我知道这是因为我的第二个for循环。只是不确定如何解决。任何帮助,将不胜感激。下面是我的代码:
public static void WriteFormattedTextToNewFile(List<string> groupedStrings)
{
string file = @"C:\Users\e011691\Desktop\New folder\formatted.txt";
StreamWriter sw = new StreamWriter(file, true);
for (int i = 0; i < ReadFile.GroupedStrings.Count; i++)
{
sw.Write($"{DateTime.Now:yyyy MM dd hh:mm:ss}\t\t");
for (int j = 0; j < 50; j++)
{
sw.Write($"{ReadFile.GroupedStrings[j]}\t");
}
sw.WriteLine();
}
sw.Close();
}
答案 0 :(得分:1)
我会给你三个选择(和奖金)。
第一个选项。使用带有迭代器块的自定义Chunk(int)
linq运算符。诀窍是内部方法使用与外部方法相同的枚举器。似乎很多代码,但是一旦有了Chunk()
方法,就可以在任何地方使用它。还要注意,此选项甚至不需要List<string>
。它将与 any IEnumerable<string>
一起使用,因为我们从未按索引引用任何元素。
public static IEnumerable<IEnumerable<T>> Chunk<T>(this IEnumerable<T> values, int chunkSize)
{
var e = values.GetEnumerator();
while (e.MoveNext())
{
yield return innerChunk(e, chunkSize);
}
}
private static IEnumerable<T> innerChunk<T>(IEnumerator<T> e, int chunkSize)
{
//If we're here, MoveNext() was already called once to advance between batches
// Need to yield the value from that call.
yield return e.Current;
//start at 1, not 0, for the first yield above
int i = 1;
while(i++ < chunkSize && e.MoveNext()) //order of these conditions matters
{
yield return e.Current;
}
}
public static void WriteFormattedTextToNewFile(IEnumerable<string> groupedStrings)
{
string file = @"C:\Users\e011691\Desktop\New folder\formatted.txt";
using (var sw = new StreamWriter(file, true))
{
foreach(var strings in groupedStrings.Chunk(50))
{
sw.Write($"{DateTime.Now:yyyy MM dd hh:mm:ss}\t\t");
foreach(var item in strings)
{
sw.Write($"{item}\t");
}
sw.WriteLine();
}
}
}
这是基本的proof of concept Chunk() actually works。
作为奖励选项,这是从第一个选项使用Chunk()
方法的另一种方法。请注意实际方法变得多么小巧而直接,但是长的全线字符串的构造可能会使这种方法的效率降低。
public static void WriteFormattedTextToNewFile(IEnumerable<string> groupedStrings)
{
string file = @"C:\Users\e011691\Desktop\New folder\formatted.txt";
using (var sw = new StreamWriter(file, true))
{
foreach(var strings in groupedStrings.Chunk(50))
{
sw.Write($"{DateTime.Now:yyyy MM dd hh:mm:ss}\t\t");
sw.WriteLine(string.Join("\t", strings));
}
}
}
第二个选项。使用单独的整数/循环跟踪。注意内循环上的额外条件,仍然使用i
值而不是j
来引用当前位置,并在内循环中递增i
。这称为控制/中断循环。请注意,我们如何能够在每行上写入结束行和初始日期值,以使它们也以正确的顺序出现在代码中:首先是页眉,然后是项目,然后是页脚,而我们无需进行复杂的条件检查
public static void WriteFormattedTextToNewFile(List<string> groupedStrings)
{
string file = @"C:\Users\e011691\Desktop\New folder\formatted.txt";
using (var sw = new StreamWriter(file, true))
{
int i = 0;
while(i < groupedStrings.Count)
{
sw.Write($"{DateTime.Now:yyyy MM dd hh:mm:ss}\t\t");
for(int j = 0; j < 50 && i < groupedStrings.Count; j++)
{
sw.Write($"{groupedStrings[i]}\t");
i++;
}
sw.WriteLine();
}
}
}
第三种选择。使用模数运算符(%
)跟踪。这个选项(或在同一循环中使用第二个j
值的类似选项)是许多人首先转向的地方,但要当心;从表面上看,此选项很难正确解决,尤其是当问题变得更加复杂时。
public static void WriteFormattedTextToNewFile(List<string> groupedStrings)
{
string file = @"C:\Users\e011691\Desktop\New folder\formatted.txt";
using (var sw = new StreamWriter(file, true))
{
for(int i = 0; i < groupedStrings.Count;i++)
{
if (i % 50 == 0)
{
if (i > 0) sw.WriteLine();
sw.Write($"{DateTime.Now:yyyy MM dd hh:mm:ss}\t\t");
}
sw.Write($"{groupedStrings[i]}\t");
}
sw.WriteLine();
}
}