views:

32

answers:

3

PREVIOUSLY: In this question someone told me how to use CompareTo to return surnames within a particular range ordered alphabetically using LINQ to Objects.

The rest of my question, which seems to have missed the initial question asking feeding frenzy, actually arose after I tested this solution. In the previous eaxample I had a list of names:

Adams
Bentham
Bickford
Gillies
Kelly
Moore
Peters
Rutherford
Smith
Taylor
Williams

And I wanted to be able to query them for all the names between Gillies and Moore for example and get:

Gillies
Kelly
Moore

This is all well and good if you want every single solitary name inbetween the goalposts returned no matter what. The problem comes in when you have a huge quantity of surnames and you want a maximum of four of the names between Gillies and Taylor returned in alphabetical order, for example.

So the desired output is:

Gillies
Kelly
Moore
Peters

However just returning four results between Gillies and Taylor could return Kelly, Peters, Smith and Taylor, or Gillies, Moore, Rutherford and Smith. Basically, the query takes you at your word and just selects any old four between the goalposts.

So, how can I get the top 4 results alphabetically. I could write a second query of course and return a subset and then select from within that... but shouldn't there be a way to integrate this behaviour into the initial query?

I've tried a couple of things with OrderBy and so far they just don't work. So it's over to you guys.

EDIT: for those two of you who've suggested using "take" I already am using take. It doesn't "take" in order, even if you use OrderBy or at least it doesn't in my query. Here it is:

var allIDs = (from cust in dc.orders
              join item in dc.order_items on cust.orderid equals item.orderid
              join del in dc.deliveries on cust.deliveryid equals del.deliveryid
              join dt in dc.deliverytypes on del.deliverytype equals dt.deliverytypeid
              where eventcode == item.itemcode
              && dt.description == "Secure Post"
              && (cust.status == "OK" || cust.status == "PB")
              && cust.surname.CompareTo(surfrom ?? " ") >= 0
              && cust.surname.CompareTo(surto ?? "zzz") <= 0
              && (cust.trackingcode == null ? false : (bool)cust.trackingcode)==false
              orderby cust.surname, cust.initials, cust.ordercode
              select cust.orderid).Distinct().Take(ordermax);

That just returns four names from between the names you've selected, not a specific four names.

A: 
GetNames(...).Take(4);

Will take the first four items in the enumerable.

Matthew Abbott
+1  A: 

Use the "Take" LINQ method to take the first 4 records:

var query = (from name in originalList
    where name.CompareTo(fromName) >= 0 && name.CompareTo(toName) <= 0
    orderby name
    select name).Take(4);
Mike Mooney
A: 

From your edit it looks like you're doing the orderby and distinct in a strange order:

This works for me (where "allMyNames" is just a List<string>).

   var ofInterest = allMyNames
                    .Distinct()
                    .Where(x => x.CompareTo(from) >= 0 && x.CompareTo(to) <= 0)
                    .OrderBy(x => x)
                    .Take(4);

I'm much happier using the extension form of LINQ :)

annakata
In the end I capitulated and wrote a complex LINQ statement to select the list, initials and surnames and then a second query in this format to implement the take requirement. Still would have been nice to return the list of ids from one query *shrugs*
bert