У меня есть следующие
data.AppendFormat("{0},",dataToAppend);
Проблема в том, что я использую его в цикле, и там будет пробная запятая. Как лучше всего убрать запятую в конце?
Должен ли я преобразовать данные в строку или ее подстроку?
У меня есть следующие
data.AppendFormat("{0},",dataToAppend);
Проблема в том, что я использую его в цикле, и там будет пробная запятая. Как лучше всего убрать запятую в конце?
Должен ли я преобразовать данные в строку или ее подстроку?
Ответы:
Самый простой и эффективный способ - выполнить эту команду:
data.Length--;
делая это, вы перемещаете указатель (т.е. последний индекс) на один символ назад, но не меняете изменчивость объекта. На самом деле, очистку также StringBuilderлучше всего выполнить с помощью Length(но на самом деле Clear()вместо этого используйте метод для ясности, потому что так выглядит его реализация):
data.Length = 0;
опять же, потому что это не меняет таблицу распределения. Думайте об этом как о том, что я не хочу больше узнавать эти байты. Теперь, даже при звонке ToString(), он не узнает ничего, кроме своего Length, ну, не может. Это изменяемый объект, который выделяет больше места, чем вы ему предоставляете, он просто построен таким образом.
data.Length = 0;: именно это и StringBuilder.Clearработает, поэтому StringBuilder.Clearдля ясности намерений лучше использовать .
Clear()делает, но забавная вещь. Это первая строка из Clear()метода. Но знаете ли вы, что интерфейс на самом деле выдает файл return this;. Вот что меня убивает. Устанавливая Length = 0изменения, ссылка у вас уже есть, зачем возвращать самому?
Appendтоже возвращается.
Просто используйте
string.Join(",", yourCollection)
Таким образом, вам не понадобится StringBuilderцикл и.
Длинное добавление об async case. По состоянию на 2019 год нередки случаи, когда данные поступают асинхронно.
Если ваши данные находятся в асинхронной коллекции, string.Joinперегрузки не происходит IAsyncEnumerable<T>. Но его легко создать вручную, взломав код изstring.Join :
public static class StringEx
{
public static async Task<string> JoinAsync<T>(string separator, IAsyncEnumerable<T> seq)
{
if (seq == null)
throw new ArgumentNullException(nameof(seq));
await using (var en = seq.GetAsyncEnumerator())
{
if (!await en.MoveNextAsync())
return string.Empty;
string firstString = en.Current?.ToString();
if (!await en.MoveNextAsync())
return firstString ?? string.Empty;
// Null separator and values are handled by the StringBuilder
var sb = new StringBuilder(256);
sb.Append(firstString);
do
{
var currentValue = en.Current;
sb.Append(separator);
if (currentValue != null)
sb.Append(currentValue);
}
while (await en.MoveNextAsync());
return sb.ToString();
}
}
}
Если данные поступают асинхронно, но интерфейс IAsyncEnumerable<T>не поддерживается (например, упомянутый в комментариях SqlDataReader), относительно легко обернуть данные в IAsyncEnumerable<T>:
async IAsyncEnumerable<(object first, object second, object product)> ExtractData(
SqlDataReader reader)
{
while (await reader.ReadAsync())
yield return (reader[0], reader[1], reader[2]);
}
и используйте это:
Task<string> Stringify(SqlDataReader reader) =>
StringEx.JoinAsync(
", ",
ExtractData(reader).Select(x => $"{x.first} * {x.second} = {x.product}"));
Для использования Selectвам необходимо использовать пакет nuget System.Interactive.Async. Здесь вы можете найти компилируемый пример.
string.Join(",", yourCollection)все еще есть ,в конце. так что приведенное выше ie string.Join(",", yourCollection)неэффективно и не удаляет его самостоятельно.
Используйте следующее после цикла.
.TrimEnd(',')
или просто измените на
string commaSeparatedList = input.Aggregate((a, x) => a + ", " + x)
string.Join(",", input)
Я предпочитаю манипулировать длиной конструктора строк:
data.Length = data.Length - 1;
data.Length--или --data.Length?
--или ++ вы можете использовать data.Length -= 1, или этот ответ тоже будет работать.
Я рекомендую вам изменить алгоритм цикла:
Вы должны использовать этот string.Joinметод, чтобы превратить коллекцию элементов в строку, разделенную запятыми. Это обеспечит отсутствие начальной или конечной запятой, а также обеспечит эффективное построение строки (без ненужных промежуточных строк).
Да, преобразовать его в строку после завершения цикла:
String str = data.ToString().TrimEnd(',');
У вас есть два варианта. Во-первых, очень простой Removeметод использования, он весьма эффективен. Второй способ - использовать ToStringс начальным и конечным индексами ( документация MSDN )
Мне понравилось использование метода расширения StringBuilder.
Самый простой способ - использовать метод Join ():
public static void Trail()
{
var list = new List<string> { "lala", "lulu", "lele" };
var data = string.Join(",", list);
}
Если вам действительно нужен StringBuilder, обрежьте конечную запятую после цикла:
data.ToString().TrimEnd(',');
data.ToString().TrimEnd(',');неэффективно
Большинство ответов в этой теме не будут работать, если вы воспользуетесь AppendLineследующим образом:
var builder = new StringBuilder();
builder.AppendLine("One,");
builder.Length--; // Won't work
Console.Write(builder.ToString());
builder = new StringBuilder();
builder.AppendLine("One,");
builder.Length += -1; // Won't work
Console.Write(builder.ToString());
builder = new StringBuilder();
builder.AppendLine("One,");
Console.Write(builder.TrimEnd(',')); // Won't work
ЗАЧЕМ??? @ (& ** (& @ !!
Проблема проста, но мне потребовалось время, чтобы разобраться в ней: потому что в конце есть еще 2 невидимых символа CRи LF(возврат каретки и перевод строки). Следовательно, нужно убрать 3 последних символа:
var builder = new StringBuilder();
builder.AppendLine("One,");
builder.Length -= 3; // This will work
Console.WriteLine(builder.ToString());
В заключении
Используйте Length--или, Length -= 1если последний вызванный вами метод был Append. Используйте, Length =- 3если вы вызывали последний метод AppendLine.
string.Join(",", yourCollection)? Изменить: добавлено в качестве ответа.