Я дам вам три варианта (и бонус).
Первый вариант.Используйте пользовательский оператор 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();
}
}
}
Вот базовое доказательство концепции, что Chunk () на самом деле работает .
В качестве бонуса, здесь есть еще один способ использовать метод 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();
}
}