У меня есть следующие
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)
? Изменить: добавлено в качестве ответа.