简体   繁体   中英

LINQ How to take one record and skip rest c#

i tried to take one record and skip rest other. my code does not throw any error but does not give any output. here is my code. so please have a look and tell me what is wrong in my code.

public sealed class Person
{
    public Person() { }
    public Person(string name,bool HQ) {
        this.Name = name;
        this.HQ = HQ;
    }

    private string _Name;
    public string Name
    {
        get { return _Name; }
        set { _Name = value; }
    }

    private bool _HQ;
    public bool HQ
    {
        get { return _HQ; }
        set { _HQ = value; }
    }
}

  protected void btn_Click(object sender, EventArgs e)
    {
        DataTable dt = new DataTable();
        dt.Columns.Add("Name",typeof(string));
        dt.Columns.Add("HQ", typeof(bool));

        DataRow dr = null;
        dr = dt.NewRow();
        dr["Name"]="Arijit";
        dr["HQ"]=true;
        dt.Rows.Add(dr);

        dr = dt.NewRow();
        dr["Name"] = "Dibyendu";
        dr["HQ"] = false;
        dt.Rows.Add(dr);

        dr = dt.NewRow();
        dr["Name"] = "Tridip";
        dr["HQ"] = false;
        dt.Rows.Add(dr);


        List<Person> oPerson1 = (from c in dt.AsEnumerable()
            select new Person
            {
                Name = c.Field<string>("Name"),
                HQ = c.Field<bool>("HQ")
            }).Skip(1).Take(2).ToList();


        List<Person> oPerson2 = (from c in dt.AsEnumerable()
            select new Person
            {
                Name = c.Field<string>("Name"),
                HQ = c.Field<bool>("HQ")
            }).Take(1).Skip(2).ToList();

    }

if you want to take first record you can call these Take(1) , First() , FirstOrDefault()

if you want to take 1 record in the middle call this : Skip(n).Take(1) where n - is number of skipped records

When you call Take(n) - no need to call Skip after that, it have already selected n records

Try this code.

Person oPerson1 = (from c in dt.AsEnumerable()
select new Person
{
    Name = c.Field<string>("Name"),
    HQ = c.Field<bool>("HQ")
}).First(); //first person in a list


Person oPerson2 = (from c in dt.AsEnumerable()
select new Person
{
    Name = c.Field<string>("Name"),
    HQ = c.Field<bool>("HQ")
}).Skip(1).First(); //second person in a list

However this code can be rewritten to be clearer:

List<Person> persons = from c in dt.AsEnumerable()
select new Person
{
    Name = c.Field<string>("Name"),
    HQ = c.Field<bool>("HQ")
};

Person oPerson1 = persons[0];
Person oPerson2 = persons[1];

I preffer to use IQueryable rather than List .

Anyway you can use Queryable.Skip to skip the no of elements you need

   IQueryable<Person> oPerson2 = (from c in dt.AsEnumerable()
            select new Person
            {
                Name = c.Field<string>("Name"),
                HQ = c.Field<bool>("HQ")
            }).Skip(2).Take(1);

Also you will find more about this in Return or Skip Elements in a Sequence (LINQ to SQL)

I'm not sure what you mean by "take one and skip the rest", but I suspect you're confusing how the LINQ operations work. They return a new sequence based on the criteria you specified, and that new sequence only has exactly what you asked for.

For example, if you have a List with three items, and you called Take(1) , you get back an IEnumerable with 1 item. There is nothing left to "skip" because there's only one element in your list. Your original data table is left unchanged -- LINQ sequences are immutable.

It sounds like all you really want to do is:

    List<Person> oPerson2 = (from c in dt.AsEnumerable()
        select new Person
        {
            Name = c.Field<string>("Name"),
            HQ = c.Field<bool>("HQ")
        }).Take(1).ToList();

Of course, this is a very common operation in LINQ so there's another, somewhat "clearer" way to do it:

    Person oPerson2 = (from c in dt.AsEnumerable()
        select new Person
        {
            Name = c.Field<string>("Name"),
            HQ = c.Field<bool>("HQ")
        }).First();

If you want to get only one record, you should replace final ToList call with First() or FirstOrDefault() they are here just for this purpose. Difference between two methods is, First() will throw exception if there is nothing to return (eg empty collection). And FirstOrDefault() will return default(T) (eg null for classes and 0 for value types).

Breaking down the chaining then:

List<Person> oPerson2 = (from c in dt.AsEnumerable()
  select new Person
  {
    Name = c.Field<string>("Name"),
    HQ = c.Field<bool>("HQ")
  }).Take(1).Skip(2).ToList();

becomes:

var tmp0 = (from c in dt.AsEnumerable()
  select new Person
  {
    Name = c.Field<string>("Name"),
    HQ = c.Field<bool>("HQ")
  });
var tmp1 = tmp0.Take(1);
var tmp2 = tmp1.Skip(2);
List<Person> oPerson2 = tmp2.ToList();

This makes it easier to see the mistake. tmp0 is an enumerable that will return every possible row when enumerated. tmp1 is an enumerable that will return just the first 1 row in tmp0 (or less if there isn't enough rows). tmp2 is an enumerable that will skip the first 2 rows in tmp1 (or less if there isn't enough rows) and then return the rest. Finally oPerson2 makes these enumerables actually return their results and stores it in a list.

From this it's clear that the mistake was .Skip(2) because it's taking a one-element enumeration and skipping up to 2 and leaving the rest, resulting in a list of max(1 - 2, 0) = 0 elements.

Leave out the Skip() and you get what you want, as "take up to 1" already entails "skip the rest".

Also .First() can be used to achive this

List<X> xlist= XBusiness.GetAllX(xname.ToString());
X lastX = xlist.First();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM