views:

82

answers:

4

I want to sort elements of a HashSet<string> and join them by a ; character.

Python interpreter version:

>>> st = {'jhg', 'uywer', 'nbcm', 'utr'}
>>> strng = ';'.join(sorted(s))
>>> strng
'ASD;anmbh;ashgg;jhghjg'

C# signature of a method I seek:

private string getVersionsSorted(HashSet<string> versions);

I can do this without using Linq, but I really want to learn it better.

Many thanks!

+2  A: 

Note that HashSets are unordered.

Simple slower version:

String.Join(";", versions.OrderBy(v => v).ToArray());

Custom faster version:

versions.OrderBy(v => v).Join(";");

///<summary>Appends a list of strings to a StringBuilder, separated by a separator string.</summary>
///<param name="builder">The StringBuilder to append to.</param>
///<param name="strings">The strings to append.</param>
///<param name="separator">A string to append between the strings.</param>
public static StringBuilder AppendJoin(this StringBuilder builder, IEnumerable<string> strings, string separator) {
    if (builder == null) throw new ArgumentNullException("builder");
    if (strings == null) throw new ArgumentNullException("strings");
    if (separator == null) throw new ArgumentNullException("separator");

    bool first = true;

    foreach (var str in strings) {
        if (first)
            first = false;
        else
            builder.Append(separator);

        builder.Append(str);
    }

    return builder;
}
///<summary>Combines a collection of strings into a single string.</summary>
public static string Join(this IEnumerable<string> strings, string separator) { return new StringBuilder().AppendJoin(strings, separator).ToString(); }

Cute Faster Version

versions.OrderBy(v => v).Aggregate(new StringBuilder(), 
    (v, sb) => sb.Append(sb.Length > 0 ? ";" : "").Append(v)
).ToString();

.Net 4.0 fastest version:

String.Join(";", versions.OrderBy(v => v));
SLaks
+3  A: 

If you have the option of using .NET 4.0, you could be using the SortedSet<T> class to begin with, which would simplify things greatly, as you just need to call string.Join on your set then.

Otherwise, if you are restricted to .NET 3.5 as it seems, try the following:

private string GetVersionsSorted(ISet<string> versions)
{
    return string.Join(",", versions.OrderBy(s => s).ToArray());
}

(Note: if you were using .NET 4.0 you can also leave out the call to ToArray, which is handy.)

Noldorin
Cool ... switching to 4.0 soon.
Hamish Grubijan
By the way, where does ISet<string> come from? This is what in-VS2008 help gives me: public class HashSet<T> : ICollection<T>, IEnumerable<T>, IEnumerable, ISerializable, IDeserializationCallback
Hamish Grubijan
`ISet<T>` is new to .Net 4.0.
SLaks
Thanks ... good idea with using an interface.
Hamish Grubijan
Oops, yeah. `ISet<T>` is new to .NET 4.0 too... I forgot how much of the code I write these days is not backwards compatible with earlier versions of .NET heh! You can get away with using `IEnumerable<T>` though...
Noldorin
What are the advantages of having ISet<T>? Why did MSFT introduce it? Because it specifies the type more precisely?
Hamish Grubijan
@Hamish: It's for a similar reason as `ICollection<T>` and `IList<T>`. It represents a common interface (contract) for all set-like classes. It becamse particularly relevant when the BCL got `HashSet` *and* `SortedSet`, so they can have a common basis.
Noldorin
+2  A: 
HashSet<string> hash = new HashSet<string>(new string[] { "b", "a", "d" });
string output = hash.OrderBy(str => str).Aggregate((a, b) => a + ";" + b);

output: a;b;d

Anthony Pegram
A: 
var versions = new HashSet<string>(new[] { "jhg", "uywer", "nbcm", "utr" });
var result = string.Join(";", versions.OrderBy(x => x).ToArray());
Console.WriteLine(result);
Darin Dimitrov
Please leave comment when down-voting, or even better modify the answer if you feel there's something wrong with it.
Darin Dimitrov
I honestly am not sure why your answer was down-voted. IT SEEMS OK TO ME.
Hamish Grubijan