Сериализация HashSet <String>с LinQ - PullRequest
1 голос
/ 16 сентября 2010

Я хотел бы взять HashSet<String> и элегантно преобразовать его в строку.Я могу повторить так:

HashSet<String> words = new HashSet<string>() { "alpha", "beta", "delta" };

string joined = "";
foreach (var w in words) 
  joined += w + ",";

if(joined.Length > 0)
  joined = joined.SubString(0,joined.Length-1); // remove final comma

Есть ли LinQ способ сделать это элегантно и эффективно?

Единственный способ, которым я могу думать об этом, - это преобразовать его вСначала массив:

HashSet<String> words = new HashSet<string>() { "alpha", "beta", "delta" };
string joined = String.Join(",",words.ToArray());

Но затем я делаю двойное преобразование.Будет ли какое-нибудь удобное выражение LinQ, которое будет эффективным и понятным?

ОТВЕТ 1 (от идеи Марра)

public static string JoinItems(this IEnumerable<string> items, string joiner) {
    StringBuilder sb = new StringBuilder("");

    foreach (var i in items) 
        sb.AppendFormat("{0}{1}",i,joiner);

    if(sb.Length>0) 
        return sb.Remove(sb.Length - joiner.Length, joiner.Length).ToString();
    else
       return sb.ToString();
}

ОТВЕТ 2 с использованием перечислителя(из решения Мартина)

public static string JoinItems<T>(this IEnumerable<T> items, string delim) {
    var sb = new StringBuilder();
    var i = items.GetEnumerator();
    if (i.MoveNext()) {
        sb.Append(i.Current);
        while (i.MoveNext()) {
            sb.Append(delim);
            sb.Append(i.Current);
        }
    }
    return sb.ToString();
}

Ответы [ 3 ]

3 голосов
/ 17 сентября 2010

Я взял ваш метод и изменил его, чтобы не нужно было удалять последнюю запятую. Я также изменил AppendFormat на Append, потому что он исключает всю работу по анализу формата каждый раз.

public static string JoinItems(this IEnumerable<string> items, string joiner)
{
    StringBuilder sb = new StringBuilder(); 
    string delim = "";

    foreach (var i in items)
    {
        sb.Append(delim);
        sb.Append(i);
        delim = joiner;
    }

    return sb.ToString(); 
} 
1 голос
/ 17 сентября 2010

Это сделает трюк без лишних копий или проверок на каждой итерации:

String JoinItems<T>(IEnumerable<T> items) {
  var stringBuilder = new StringBuilder();
  var i = items.GetEnumerator();
  if (i.MoveNext()) {
    stringBuilder.Append(i.Current);
    while (i.MoveNext()) {
      stringBuilder.Append(", ");
      stringBuilder.Append(i.Current);
    }
  }
  return stringBuilder.ToString();
}
1 голос
/ 16 сентября 2010

Я не вижу двойного преобразования в вашей строке String.Join ().Я вижу одно преобразование ToArray (), которое не страшно, и затем он выполняет String.Join (), который работает хорошо.

В .Net существует String.Join () 4, который принимает IEnumerable, который будет работать без преобразования.Если вы используете более старую версию фреймворка, вы можете написать свой собственный метод расширения для строки, которая принимает разделитель в качестве параметра «this», а затем присоединяется к IEnumerable.Обязательно и используйте stringbuilder для производительности.

...