tags:

views:

55

answers:

6

I have a property on a class that is an ISet. I'm trying to get the results of a linq query into that property, but can't figure out how to do so.

Basically, looking for the last part of this:

ISet<T> foo = new HashedSet<T>();
foo = (from x in bar.Items select x).SOMETHING;

Could also do this:

HashSet<T> foo = new HashSet<T>();
foo = (from x in bar.Items select x).SOMETHING;

Edit: This is what I ended up doing:

    public static HashSet<T> ToHashSet<T>(this IEnumerable<T> source)
    {
        return new HashSet<T>(source);
    }

    public static HashedSet<T> ToHashedSet<T>(this IEnumerable<T> source)
    {
        return new HashedSet<T>(source.ToHashSet());
    }
+4  A: 

Just pass your IEnumerable into the constructor for HashSet.

HashSet<T> foo = new HashSet<T>(from x in bar.Items select x);
Joel Mueller
How are you going to cope with a projection which results in an anonymous type?
Jon Skeet
@Jon, I'd assume that's YAGNI until confirmed otherwise.
Anthony Pegram
Clearly I'm not. Fortunately, in this particular example, I don't need to.
Joel Mueller
@Jon the type is specified by OP (the first line wouldn't compiler otherwise) so in this case I have to agree it's YAGNI for now
Rune FS
@Rune FS: In this case, I suspect the sample code isn't realistic. It's pretty rare to have a type parameter T but know that each item of `bar.Items` is going to be `T`. Given how easy it is to make this general purpose, and how frequently anonymous types come up in LINQ, I think it's worth taking the extra step.
Jon Skeet
@Jon agreed and that's the reason why got +1. It might not be necessary in this particular case but as a general example (and thus good for all googlers) the approach of wrapping it in a generic method serves as a good example
Rune FS
+4  A: 

I don't think there's anything built in which does this... but it's really easy to write an extension method:

public static class Extensions
{
    public static HashSet<T> ToHashSet<T>(this IEnumerable<T> source)
    {
        return new HashSet<T>(source);
    }
}

Note that you really do want an extension method (or at least a generic method of some form) here, because you may not be able to express the type of T explicitly:

var query = from i in Enumerable.Range(0, 10)
            select new { i, j = i + 1 };
var resultSet = query.ToHashSet();

You can't do that with an explicit call to the HashSet<T> constructor. We're relying on type inference for generic methods to do it for us.

Now you could choose to name it ToSet and return ISet<T> - but I'd stick with ToHashSet and the concrete type. This is consistent with the standard LINQ operators (ToDictionary, ToList) and allows for future expansion (e.g. ToSortedSet). You may also want to provide an overload specifying the comparison to use.

Jon Skeet
Good point on anonymous types. However, do anonymous types have useful overrides of `GetHashCode` and `Equals`? If not, they're not going to be much good in a HashSet...
Joel Mueller
@Joel: Yes, they do. Otherwise all kinds of things would fail. Admittedly they only use the default equality comparers for the component types, but that's usually good enough.
Jon Skeet
Good to know. In that case, yes, the extension method would be more generally useful than using the constructor directly.
Joel Mueller
A: 

That's pretty simple :)

var foo = new HashSet<T>(from x in bar.Items select x);

and yes T is the type specified by OP :)

Rune FS
That doesn't specify a type argument.
Jon Skeet
Lol that has got to be the harshest down vote of the day:). To me there's exactly the same info now. Beats me why the type inference system isn't already inferring that type anyways :)
Rune FS
@Rune FS: Undone now... but it's actually pretty significant precisely *because* you don't get type inference. See my answer.
Jon Skeet
I can't remember seeing it on Eric's blog why inference on constructors is not a part of the spec's do you know why?
Rune FS
@Rune FS: Not sure, to be honest.
Jon Skeet
A: 

You could just use the IEnumerable HashSet constructor.

HashSet<T> foo = new HashSet<T>((from x in bar.Items select x).ToArray());
Steve Danner
The `ToArray` there doesn't accomplish anything except making the computer do extra work.
Joel Mueller
Keeping them busy is the only way we'll keep them from rising against us though!
Jimmy
+1  A: 

As @Joel stated, you can just pass your enumerable in. If you want to do an extension method, you can do:

public static HashSet<T> ToHashSet<T>(this IEnumerable<T> items)
{
    return new HashSet<T>(items);
}
Matthew Abbott
Lol, Skeeted again :P
Matthew Abbott
+1 b/c you deserve something for only being 2 minutes behind the Skeet.
Gabe Moothart
A: 

Jon's answer is perfect. The only caveat is that, using NHibernate's HashedSet, I need to convert the results to a collection. Is there an optimal way to do this?

ISet<string> bla = new HashedSet<string>((from b in strings select b).ToArray()); 

or

ISet<string> bla = new HashedSet<string>((from b in strings select b).ToList()); 

Or am I missing something else?

Jamie
@Jamie: `ToList` is generally more efficient than `ToArray`. Does it just need to implement `ICollection<T>`?
Jon Skeet
Correct. I ended up going with your method, then using that to do the ToHashedSet (see edit on original question). Thanks for your help.
Jamie