views:

212

answers:

5

Hi All,

I know it's a highly subjective issue (and one that may well see a flurry of 'close it' votes), hence pointing it at the CW and adding the disclaimer.

Anyway, I've been working thro a project in asp.net mvc using subsonic and was suddenly (again) struck with the elegence and 'ruggedness' of the linq implementation that lies on top of both subsonic and the general linq to objects library. This occasioned me look a little closer into my code and made me realise that some of the tasks that I was using linq for would be endlessly complex (or 'near impossible' - subjective of course) if attempted in a traditional manner (this of course could well be a limitation in me).

Anyway, as a result of this, I thought it would be interesting to see what problems folk had encountered that were elegently solved by using linq.

To kick off, one scenario that i recently had involved an entity that had a common 'unitid' property on it. i wanted to be able to group a set of these in order to manipulate and examine this set when split out to thier appropriate 'unitid' groups. After much thought, i arrived at this simple little linq one liner:

// the base collection of the objects - not grouped in any way
IQueryable<ShareholderRSP> rsps = validshareholderPounds
    .Where(x => x.Balance > 0)
    .OrderBy(x => x.RequestYear);

// the one-liner in question to group the objects by unitid
IList<IGrouping<string, ShareholderRSP>> groupedRSP =
     rsps.ToList().GroupBy(t => t.UnitID.ToString()).ToList();

which i was then able to use as:

foreach (var rspGrpItem in groupedRSP)
{
    foreach (var shareholderRSP in rspGrpItem)
    {
       // note, i could have also iterated this list too 
       // which is a base object contained within the collection
       // underneath the group collection item
    }
    // create a top level summary grouped by unitid
    // usedPounds is a variable created earlier on in the piece
    bookingConfirm.RSPUnitSelect.Add(
        new BookingConfirmRSPSelect
        {
            TotalBeforeUse = rspGrpItem.Sum(rsp => rsp.Balance),
            TotalAfterUse = rspGrpItem.Sum(rsp => rsp.Balance) - usedPounds,
            UnitNo = rspGrpItem.Key
        }
    );
}

Had i attempted this in a traditional fashion, my logic would (in my opinion) have been more cumbersome and less able to adapt to any changes in the underlying object model.

Hopefully, if not quite a discussion sparker, this has highlighted my 'joy' at using linq.

All the best - hopefully the omission of the object model in question above won't detract from the purpose of the example, as hopefully the intention reveals all.

Looking fwd to some fine examples.

jim

+9  A: 

Simple trick : a quick way to generate a sequence of random numbers :

var randomNumbers = Enumerable.Repeat(new Random(), 10).Select(r => r.Next());
Thomas Levesque
nice one thomas...
jim
doesn't it instantiate ten `Random` classes? if yes, this is a very bad way to generate random numbers.
Oliver
No, it creates only 1 instance of Random, and repeat it 10 times
Thomas Levesque
In that case i learned another cute function today i didn't know before. ;)
Oliver
thomas - you could also use: var randomNumbers = Enumerable.Select(Enumerable.Repeat(new Random(), 10), r => r.Next());
jim
Yes, but that would be strange... Select is an extension method, it's quite unnatural to use is as a plain static method. And I don't find it more readable...
Thomas Levesque
thomas - true. just is an 'interesting' spin on the various ways that linq can be (ab)used..
jim
+1  A: 

Often you just use a foreach or some linq statement, but within it you need additionally to the element itself the index. For this exists an overload of the select-statement.

var itemsWithIndex = myList.Select((item, index) => new { Item = item, Index = index });

foreach(var element in itemsWithIndex)
{
    Console.WriteLine("{0,-2} {1}", element.Index, element.Item.ToString());
}
Oliver
A: 

The project Euler problem 8 - Find the greatest product of five consecutive digits in the 1000-digit number. i solved Yesterday using Linq & Lambda

        //orgStr - string variable holding 1000 digit number
        var max= Enumerable.Range(0, orgStr.Length - 5).Select(idx =>
        {
            return orgStr.Substring(idx, 5).Select(x => Int64.Parse(x.ToString()))
                .ToArray().Aggregate((a, b) => a * b);

        }).ToArray().Max();

Its pretty explanatory i think

Cheers

Ramesh Vel
aye - mind now melting :)
jim
Why the two calls to ToArray()?
Henrik
@Henrik, good catch, 2nd ToArray() not needed.... :(
Ramesh Vel
You know, the project euler questions are probably a pretty fun way to learn linq.
quillbreaker
quillbreaker, indeed ! Although it's usually not the most efficient way of solving the problems, it's a very intuitive approach
Thomas Levesque
+2  A: 

To calculate the union of a collection of rectangles:

var union = rects.Aggregate(Rectangle.Empty, Rectangle.Union);
jdv
I would rather use Rectangle.Empty as the seed... the result is the same, but it shows the intent more clearly
Thomas Levesque
@Thomas: You're right. I fixed that. I dont have the project in front of me right now and I wasn't sure if al Rectangle types implement Empty.
jdv
A: 

was answering a question re Array.IndexOf() here on SO and 'garbled' this together:):

.net we'd 'possibly' do this normally:

string[] testArray = { "cat", "dog", "banana", "orange" };
var indexOffset = Array.IndexOf(testArray, "banana");

an 'academic' alternative in linq could be:

string[] testArray = { "cat", "dog", "banana", "orange" };
var firstItem = testArray.Select((item, index) => new
{
    ItemName = item,
    Position = index

}).Where(i => i.ItemName == "banana")
  .First()
  .Position;

not sure what perfomance penalties we'd see here, but one more way to skin the cat (or dog or banana)

jim

jim