У мене таке
data.AppendFormat("{0},",dataToAppend);
Проблема з цим полягає в тому, що я використовую його в циклі, і буде випробовувана кома. Який найкращий спосіб видалити кінцеву кому?
Чи потрібно змінювати дані на рядок, що є їх підрядком?
У мене таке
data.AppendFormat("{0},",dataToAppend);
Проблема з цим полягає в тому, що я використовую його в циклі, і буде випробовувана кома. Який найкращий спосіб видалити кінцеву кому?
Чи потрібно змінювати дані на рядок, що є їх підрядком?
Відповіді:
Найпростіший та найефективніший спосіб - виконати цю команду:
data.Length--;
роблячи це, ви переміщуєте покажчик (тобто останній індекс) назад на один символ, але ви не змінюєте змінність об'єкта. Насправді очищення a StringBuilder
також найкраще зробити Length
(але насправді використовуйте Clear()
метод для ясності, тому що так виглядає його реалізація):
data.Length = 0;
знову ж таки, оскільки це не змінює таблицю розподілу. Подумайте про це, як про те, що я більше не хочу розпізнавати ці байти. Тепер, навіть зателефонувавши ToString()
, він не розпізнає нічого минулого Length
, ну, не може. Це змінний об’єкт, який виділяє більше місця, ніж те, що ви йому надаєте, він просто побудований таким чином.
data.Length = 0;
: це саме те, що StringBuilder.Clear
робить, тому переважно використовувати StringBuilder.Clear
для ясності намірів.
Clear()
так, але смішно. Це перший рядок з Clear()
методу. Але, чи знали ви, що інтерфейс насправді видає a return this;
. Зараз це те, що мене вбиває. Встановлюючи Length = 0
зміни, посилання у вас вже є, навіщо повертатись самому?
Append
також повертається.
Просто використовуйте
string.Join(",", yourCollection)
Таким чином, вам не потрібен StringBuilder
цикл and.
Довге додавання про асинхронний випадок. Станом на 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)
все ще має в ,
кінці. отже вищезазначене 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 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)
? Редагувати: додано як відповідь.