LINQ:“ มี” และแบบสอบถามแลมบ์ดา


168

ฉันมีที่เรียกว่าList<BuildingStatus> buildingStatusฉันต้องการตรวจสอบว่ามีสถานะที่รหัสถ่าน (คืนโดยGetCharCode()) เท่ากับตัวแปรบางอย่างหรือv.Statusไม่

มีวิธีในการทำเช่นนี้ตามบรรทัดของรหัส (ไม่รวบรวม) ด้านล่าง?

buildingStatus.Contains(item => item.GetCharValue() == v.Status)

คำตอบ:


320

ใช้Any()แทนContains():

buildingStatus.Any(item => item.GetCharValue() == v.Status)

13
ดี ฉันสงสัยอยู่ตลอดว่าทำไมใน Earth Linq ไม่ได้มีContains()วิธีการและจากนั้นฉันก็รู้ว่ามันควรจะเป็นAny()แทน +1
โนโลนาร์

38

วิธีการขยาย Linq อะไรก็ได้ที่เหมาะกับคุณ ...

buildingStatus.Any(item => item.GetCharValue() == v.Status)

4

นี่คือวิธีที่คุณสามารถใช้Containsเพื่อให้บรรลุสิ่งที่คุณต้องการ:

buildingStatus.Select(item => item.GetCharValue()).Contains(v.Status) สิ่งนี้จะคืนค่าบูลีน


3

ฉันไม่แน่ใจว่าสิ่งที่คุณกำลังมองหา แต่โปรแกรมนี้:

    public class Building
    {
        public enum StatusType
        {
            open,
            closed,
            weird,
        };

        public string Name { get; set; }
        public StatusType Status { get; set; }
    }

    public static List <Building> buildingList = new List<Building> ()
    {
        new Building () { Name = "one", Status = Building.StatusType.open },
        new Building () { Name = "two", Status = Building.StatusType.closed },
        new Building () { Name = "three", Status = Building.StatusType.weird },

        new Building () { Name = "four", Status = Building.StatusType.open },
        new Building () { Name = "five", Status = Building.StatusType.closed },
        new Building () { Name = "six", Status = Building.StatusType.weird },
    };

    static void Main (string [] args)
    {
        var statusList = new List<Building.StatusType> () { Building.StatusType.open, Building.StatusType.closed };

        var q = from building in buildingList
                where statusList.Contains (building.Status)
                select building;

        foreach ( var b in q )
            Console.WriteLine ("{0}: {1}", b.Name, b.Status);
    }

สร้างผลลัพธ์ที่คาดหวัง:

one: open
two: closed
four: open
five: closed

โปรแกรมนี้เปรียบเทียบการแทนค่าสตริงของ enum และสร้างเอาต์พุตเดียวกัน:

    public class Building
    {
        public enum StatusType
        {
            open,
            closed,
            weird,
        };

        public string Name { get; set; }
        public string Status { get; set; }
    }

    public static List <Building> buildingList = new List<Building> ()
    {
        new Building () { Name = "one", Status = "open" },
        new Building () { Name = "two", Status = "closed" },
        new Building () { Name = "three", Status = "weird" },

        new Building () { Name = "four", Status = "open" },
        new Building () { Name = "five", Status = "closed" },
        new Building () { Name = "six", Status = "weird" },
    };

    static void Main (string [] args)
    {
        var statusList = new List<Building.StatusType> () { Building.StatusType.open, Building.StatusType.closed };
        var statusStringList = statusList.ConvertAll <string> (st => st.ToString ());

        var q = from building in buildingList
                where statusStringList.Contains (building.Status)
                select building;

        foreach ( var b in q )
            Console.WriteLine ("{0}: {1}", b.Name, b.Status);

        Console.ReadKey ();
    }

ฉันสร้างวิธีการขยายนี้เพื่อแปลง IEnumerable เป็นอันหนึ่ง แต่ไม่แน่ใจว่ามีประสิทธิภาพแค่ไหน มันอาจสร้างรายการเบื้องหลัง

public static IEnumerable <TResult> ConvertEach (IEnumerable <TSource> sources, Func <TSource,TResult> convert)
{
    foreach ( TSource source in sources )
        yield return convert (source);
}

จากนั้นคุณสามารถเปลี่ยนข้อที่เป็น:

where statusList.ConvertEach <string> (status => status.GetCharValue()).
    Contains (v.Status)

และข้ามการสร้างList<string>ด้วยConvertAll ()ที่จุดเริ่มต้น


ขอบคุณ larry ที่ทำงานนี่คือสิ่งที่ฉันทำโดยอ้างถึงรหัสของคุณ ... แต่มันจะดีถ้าเป็นไปได้ถ้าฉันไม่ต้องสร้างรายการใหม่ ???? // ToList ใช้แล้วเพราะเป็น ILIST และรัน GetCharValue ของฉัน // สิ่งนี้จะสร้างรายการ "ใหม่" ที่มี var var สถานะStringList = building.ToList ถ่านของฉัน () ConvertAll <char> (st => st.GetCharValue ()); var test = จาก v ใน qry โดยที่ statusStringList.Contains (v.Status) เลือก v; ผลงานทั้งหมดที่ฉันบอกว่ามันจะดีไม่ต้องทำรายการใหม่หรือใช้แลมบ์ดาภายในประกอบด้วย แต่ดูเหมือนจะเป็นไปไม่ได้?
ทำเครื่องหมายสมิ ธ

ฉันถือว่าทรัพย์สินสถานะเป็นสตริง; คุณจึงต้องแปลงสถานะเป็น enums เพื่อการเปรียบเทียบแต่ละครั้ง คุณอาจแปลงพวกมันหนึ่งครั้งในตอนเริ่มต้นและทำได้ด้วย
XXXXX

ฉันได้ทำการแก้ไขที่ทำให้คำถามง่ายขึ้นอย่างมาก แต่ในการทำเช่นนี้คำตอบที่ไม่ถูกต้องจะเรียงลำดับ ขออภัยเกี่ยวกับเรื่องนี้ แต่ฉันคิดว่ามันเป็นภาพรวมที่ดีขึ้น
Mark Amery

-1

ถ้าฉันเข้าใจถูกต้องคุณต้องแปลงประเภท (ค่าถ่าน) ที่คุณเก็บไว้ในรายการอาคารเป็นประเภท (enum) ที่คุณเก็บไว้ในรายการ buildingStatus

(สำหรับแต่ละสถานะในรายการสิ่งก่อสร้าง // ค่าตัวอักษร // สถานะนั้นมีอยู่ในรายการ buildingStatus // enum value //)

public static IQueryable<Building> WithStatus(this IQueryable<Building> qry,  
IList<BuildingStatuses> buildingStatus) 
{ 
    return from v in qry
           where ContainsStatus(v.Status)
           select v;
} 


private bool ContainsStatus(v.Status)
{
    foreach(Enum value in Enum.GetValues(typeof(buildingStatus)))
    {
        If v.Status == value.GetCharValue();
            return true;
    }

    return false;
}

-1; ในขณะที่การแก้ไขคำถามของฉันทำให้คำตอบนี้มีความน่าเชื่อถือเล็กน้อยโดยการลบการอ้างอิงทั้งหมดBuildingออกจากคำถาม แต่นี่ก็ใช้งานไม่ได้ foreach(Enum value in Enum.GetValues(typeof(buildingStatus)))ไร้สาระ
Mark Amery
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.