ค้นหารายการในรายการโดย LINQ?


226

ที่นี่ฉันมีตัวอย่างง่ายๆในการค้นหารายการในรายการสตริง โดยปกติฉันจะใช้สำหรับการวนซ้ำหรือการมอบสิทธิ์แบบไม่ระบุชื่อเพื่อทำสิ่งนี้:

int GetItemIndex(string search)
{
   int found = -1;
   if ( _list != null )
   {
     foreach (string item in _list) // _list is an instance of List<string>
     { 
        found++;
        if ( string.Equals(search, item) )
        {
           break;
        }
      }
      /* use anonymous delegate
      string foundItem = _list.Find( delegate(string item) {
         found++;
         return string.Equals(search, item);
      });
      */
   }
   return found;
}

LINQ เป็นของใหม่สำหรับฉัน ฉันอยากรู้ว่าฉันสามารถใช้ LINQ เพื่อค้นหารายการในรายการได้หรือไม่ ถ้าเป็นไปได้อย่างไร


เยี่ยมมาก อย่างไรก็ตามสิ่งเหล่านี้ล้วนเป็นสไตล์การแสดงออกแลมด้า ฉันใช้รายการง่ายๆที่นี่ รายการอาจเป็นคลาสที่มีคุณสมบัติหลายอย่างและบางรายการใช้สำหรับการค้นหา ดังนั้นวิธี LINQ ในการค้นหาเช่น "จาก .. ใน ... ที่ ... เลือก ... "
David.Chu.ca

ไม่ได้ขอโทษ วิธีการเหล่านี้ส่วนใหญ่ (First, Single, Any, ... ) ไม่สามารถแปลโดยตรงไปยังแบบฟอร์มนั้น
R. Martinho Fernandes

ไม่เป็นไรจริงคุณจะได้รับการกำจัดของ lambdas สำหรับบางกรณี ...
อาร์มาตินเฟอร์นันเด

คำตอบที่ดี! ฉันแค่อยากได้รสชาติของการสืบค้น LINQ จากกรณีการแจงนับ
David.Chu.ca

คำตอบ:


478

มีหลายวิธี (โปรดทราบว่านี่ไม่ใช่รายการที่สมบูรณ์)

1) Singleจะส่งคืนผลลัพธ์เดียว แต่จะโยนข้อยกเว้นหากพบว่าไม่มีอย่างน้อยหนึ่งอย่าง (ซึ่งอาจจะใช่หรือไม่ใช่ในสิ่งที่คุณต้องการ):

string search = "lookforme";
List<string> myList = new List<string>();
string result = myList.Single(s => s == search);

หมายเหตุSingleOrDefault()จะทำงานเหมือนกันยกเว้นจะส่งคืนค่า null สำหรับประเภทการอ้างอิงหรือค่าเริ่มต้นสำหรับประเภทค่าแทนที่จะทิ้งข้อยกเว้น

2) ที่ไหนจะส่งคืนรายการทั้งหมดที่ตรงกับเกณฑ์ของคุณดังนั้นคุณอาจได้รับ IEnumerable ด้วยองค์ประกอบเดียว:

IEnumerable<string> results = myList.Where(s => s == search);

3) ขั้นแรกจะคืนรายการแรกที่ตรงกับเกณฑ์ของคุณ:

string result = myList.First(s => s == search);

หมายเหตุFirstOrDefault()จะทำงานเหมือนกันยกเว้นจะส่งคืนค่า null สำหรับประเภทการอ้างอิงหรือค่าเริ่มต้นสำหรับประเภทค่าแทนที่จะทิ้งข้อยกเว้น


35
คำตอบที่ดี ฉันพบว่า SingleOrDefault เป็นคำตอบที่ฉันเลือก - เช่นเดียวกับ Single แต่ส่งคืน 'null' หากไม่พบ
Eddie Parker

2
ฉันไม่รู้จัก Single () หรือ SingleOrDefault () มีประโยชน์มาก.
draconis

วิธีการเหล่านี้สามารถใช้กับคอลเลกชันอื่น ๆ ได้เช่นกันReadOnlyCollectionหรือObservableCollectionไม่?
yellavon

@yellavon เหล่านี้เป็นวิธีการขยายในประเภทใด ๆ ที่ดำเนินการIEnumerable<T>หรือIQueryable<T>
Rex M

4
สิ่งหนึ่งที่ควรทราบเกี่ยวกับการใช้ SingleOrDefault คือเนื่องจากมีข้อยกเว้นหากมีการแข่งขันมากกว่าหนึ่งรายการอยู่ในรายการจึงต้องวนซ้ำทุกรายการโดยที่ FirstOrDefault จะหยุดค้นหาเมื่อพบคู่แรก msdn.microsoft.com/en-us/library/bb342451(v=vs.110).aspx
DavidWainwright

73

หากคุณต้องการดัชนีขององค์ประกอบสิ่งนี้จะทำ:

int index = list.Select((item, i) => new { Item = item, Index = i })
                .First(x => x.Item == search).Index;

// or
var tagged = list.Select((item, i) => new { Item = item, Index = i });
int index = (from pair in tagged
            where pair.Item == search
            select pair.Index).First();

คุณไม่สามารถกำจัดแลมบ์ดาในรอบแรกได้

โปรดทราบว่าสิ่งนี้จะเกิดขึ้นหากรายการนั้นไม่มีอยู่ วิธีนี้จะช่วยแก้ปัญหาโดยหันไปใช้ ints เป็นโมฆะ:

var tagged = list.Select((item, i) => new { Item = item, Index = (int?)i });
int? index = (from pair in tagged
            where pair.Item == search
            select pair.Index).FirstOrDefault();

หากคุณต้องการรายการ:

// Throws if not found
var item = list.First(item => item == search);
// or
var item = (from item in list
            where item == search
            select item).First();

// Null if not found
var item = list.FirstOrDefault(item => item == search);
// or
var item = (from item in list
            where item == search
            select item).FirstOrDefault();

หากคุณต้องการนับจำนวนรายการที่ตรงกับ:

int count = list.Count(item => item == search);
// or
int count = (from item in list
            where item == search
            select item).Count();

หากคุณต้องการรายการทั้งหมดที่ตรงกับ:

var items = list.Where(item => item == search);
// or
var items = from item in list
            where item == search
            select item;

และอย่าลืมตรวจสอบรายชื่อnullในกรณีเหล่านี้

หรือใช้แทน(list ?? Enumerable.Empty<string>())list

ขอบคุณพาเวลที่ช่วยแสดงความคิดเห็น


2
สองคะแนน ครั้งแรกที่มีความจำเป็นจริงที่จะใช้string.Equalsที่นี่ - ==ผิดอะไรกับ ประการที่สองฉันยังพูดถึงFirstOrDefault(สำหรับกรณีที่รายการอาจไม่มีอยู่) และSelectมีดัชนีเพื่อครอบคลุมกรณีที่จำเป็นต้องมีดัชนีของรายการ (เนื่องจากอยู่ในตัวอย่างในคำถามด้วยตัวเอง)
Pavel Minaev

ฉันยังไม่มีความสุข ตัวอย่างของฉันไม่มีดัชนี -1 (ไม่พบ) ข้อเสนอแนะใด ๆ
R. Martinho Fernandes

นอกจากการตรวจสอบว่ามันอยู่กับถ้าก่อน
R. Martinho Fernandes

ฉันต้องตรวจสอบว่ารายการนั้นว่างก่อนหรือไม่?
David.Chu.ca

เลือกทุ่มArgumentNullExceptionถ้าแหล่งที่มาเป็นโมฆะ
R. Martinho Fernandes

13

ถ้าเป็นจริงList<string>คุณไม่ต้องการ LINQ เพียงใช้:

int GetItemIndex(string search)
{
    return _list == null ? -1 : _list.IndexOf(search);
}

หากคุณกำลังมองหารายการลอง:

string GetItem(string search)
{
    return _list == null ? null : _list.FirstOrDefault(s => s.Equals(search));
}

1
ตามตรรกะของตัวอย่างแรกเราสามารถใช้_list.Find(search)สำหรับวินาที
jwg

12

คุณต้องการไอเท็มในรายการหรือไอเท็มจริงหรือไม่ (ถือว่าเป็นของไอเท็มเอง)

นี่คือตัวเลือกมากมายสำหรับคุณ:

string result = _list.First(s => s == search);

string result = (from s in _list
                 where s == search
                 select s).Single();

string result = _list.Find(search);

int result = _list.IndexOf(search);

โอ้โฮ ... บางคนเร็วสุดหนึ่งไก;)
Kelsey

วิธีการเกี่ยวกับดัชนีเป็นค่าตอบแทนหรือไม่
David.Chu.ca

และฉันต้องตรวจสอบว่า _list เป็นโมฆะในรูปแบบจาก .. ใน _list ... หรือไม่
David.Chu.ca

6

วิธีนี้ง่ายกว่าและปลอดภัยกว่า

var lOrders = new List<string>();

bool insertOrderNew = lOrders.Find(r => r == "1234") == null ? true : false


1
ฉันคิดว่าเราไม่ต้องการแม้แต่true : falseน้อยด้านล่างควรทำงานเหมือนกัน bool insertOrderNew = lOrders.Find(r => r == "1234") == null;
Vbp

5

แล้วไงIndexOfล่ะ

ค้นหาวัตถุที่ระบุและส่งกลับดัชนีของการเกิดขึ้นครั้งแรกภายในรายการ

ตัวอย่างเช่น

> var boys = new List<string>{"Harry", "Ron", "Neville"};  
> boys.IndexOf("Neville")  
2
> boys[2] == "Neville"
True

โปรดทราบว่ามันจะส่งกลับ -1 ถ้าค่าไม่เกิดขึ้นในรายการ

> boys.IndexOf("Hermione")  
-1

2

ฉันเคยใช้พจนานุกรมซึ่งเป็นรายการดัชนีที่จะให้สิ่งที่ฉันต้องการเมื่อฉันต้องการ

Dictionary<string, int> margins = new Dictionary<string, int>();
margins.Add("left", 10);
margins.Add("right", 10);
margins.Add("top", 20);
margins.Add("bottom", 30);

เมื่อใดก็ตามที่ฉันต้องการเข้าถึงค่าระยะขอบของฉันฉันจะพูดถึงพจนานุกรมของฉัน:

int xStartPos = margins["left"];
int xLimitPos = margins["right"];
int yStartPos = margins["top"];
int yLimitPos = margins["bottom"];

ดังนั้นพจนานุกรมจะมีประโยชน์ขึ้นอยู่กับสิ่งที่คุณทำ


คำตอบที่ดีสำหรับคำถามอื่น
jwg

2

นี่เป็นวิธีหนึ่งในการเขียนวิธีการของคุณใหม่เพื่อใช้ LINQ:

public static int GetItemIndex(string search)
{
    List<string> _list = new List<string>() { "one", "two", "three" };

    var result = _list.Select((Value, Index) => new { Value, Index })
            .SingleOrDefault(l => l.Value == search);

    return result == null ? -1 : result.Index;
}

ดังนั้นการโทรด้วย

GetItemIndex("two")จะกลับมา1,

และ

GetItemIndex("notthere")-1จะกลับมา

การอ้างอิง: linqsamples.com


1

ลองรหัสนี้:

return context.EntitytableName.AsEnumerable().Find(p => p.LoginID.Equals(loginID) && p.Password.Equals(password)).Select(p => new ModelTableName{ FirstName = p.FirstName, UserID = p.UserID });

1

หากเราต้องการค้นหาองค์ประกอบจากรายการเราสามารถใช้วิธีFindและFindAllส่วนขยายได้ แต่มีความแตกต่างเล็กน้อยระหว่างองค์ประกอบเหล่านั้น นี่คือตัวอย่าง

 List<int> items = new List<int>() { 10, 9, 8, 4, 8, 7, 8 };

  // It will return only one 8 as Find returns only the first occurrence of matched elements.
     var result = items.Find(ls => ls == 8);      
 // this will returns three {8,8,8} as FindAll returns all the matched elements.
      var result1 = items.FindAll(ls => ls == 8); 

1

สิ่งนี้จะช่วยคุณในการรับค่าแรกหรือค่าเริ่มต้นในการค้นหารายการ Linq ของคุณ

var results = _List.Where(item => item == search).FirstOrDefault();

การค้นหานี้จะค้นหาค่าแรกหรือค่าเริ่มต้นที่จะส่งคืน


0

คุณต้องการค้นหาวัตถุในรายการวัตถุ

สิ่งนี้จะช่วยคุณในการรับค่าแรกหรือค่าเริ่มต้นในการค้นหารายการ Linq ของคุณ

var item = list.FirstOrDefault(items =>  items.Reference == ent.BackToBackExternalReferenceId);

หรือ

var item = (from items in list
    where items.Reference == ent.BackToBackExternalReferenceId
    select items).FirstOrDefault();

0

คุณสามารถใช้ FirstOfDefault กับส่วนขยาย Where Linq เพื่อรับคลาส MessageAction จาก IEnumerable Reme

var action = Message.Actions.Where (e => e.targetByName == className) .FirstOrDefault ();

ที่ไหน

รายการการกระทำ {รับ; ตั้ง; }

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.