ตรวจสอบว่ารายการมีองค์ประกอบที่มีสตริงและรับองค์ประกอบนั้น


146

ในขณะที่ค้นหาคำตอบสำหรับคำถามนี้ฉันพบคนที่คล้ายกันโดยใช้ LINQ แต่ฉันไม่สามารถเข้าใจพวกเขาได้อย่างสมบูรณ์ (และใช้พวกเขา) เนื่องจากฉันไม่คุ้นเคย สิ่งที่ฉันต้องการโดยพื้นฐานคือ:

  1. ตรวจสอบว่าองค์ประกอบใด ๆ ของรายการมีสตริงเฉพาะ
  2. ถ้าเป็นเช่นนั้นรับองค์ประกอบนั้น

ฉันไม่รู้จะทำอย่างไร สิ่งที่ฉันสามารถทำได้คือ (ไม่ทำงานแน่นอน):

if (myList.Contains(myString))
    string element = myList.ElementAt(myList.IndexOf(myString));

ฉันรู้ว่าทำไมมันไม่ทำงาน:

  • myList.Contains()ไม่ส่งคืนtrueเนื่องจากจะตรวจสอบว่าองค์ประกอบทั้งหมดของรายการตรงกับสตริงที่ฉันระบุ
  • myList.IndexOf() จะไม่พบสิ่งที่เกิดขึ้นเนื่องจากเป็นกรณีอีกครั้งมันจะตรวจสอบองค์ประกอบที่ตรงกับสตริง

ยังฉันไม่มีเงื่อนงำวิธีการแก้ปัญหานี้ แต่ฉันคิดว่าฉันจะต้องใช้ LINQ ตามที่แนะนำในคำถามที่คล้ายกันเพื่อเหมือง ที่ถูกกล่าวว่าถ้าเป็นกรณีที่นี่ฉันต้องการให้ผู้ตอบเพื่ออธิบายการใช้งาน LINQ ในตัวอย่างของพวกเขา (ดังที่ฉันบอกว่าฉันไม่ได้ใส่ใจกับมันในเวลาที่ฉันใช้ C #) ขอบคุณล่วงหน้าพวก (และ gals?)

แก้ไข: ฉันได้มาด้วยวิธีการแก้ปัญหา; เพียงแค่วนดูรายการตรวจสอบว่าองค์ประกอบปัจจุบันมีสตริงและจากนั้นตั้งค่าสตริงเท่ากับองค์ประกอบปัจจุบัน ฉันสงสัยว่ามีวิธีที่มีประสิทธิภาพมากกว่านี้หรือไม่?

string myString = "bla";
string element = "";

for (int i = 0; i < myList.Count; i++)
{
    if (myList[i].Contains(myString))
        element = myList[i];
}

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

อาจมีหลายสายในรายการของคุณที่มีสตริงmyStringในวงปัจจุบันของคุณคุณจะได้รับองค์ประกอบสุดท้าย มันขึ้นอยู่กับคุณถ้าคุณต้องการหาคนแรกหรือคนสุดท้ายถ้าคุณแค่อยากจะหาคนแรกจากนั้นก็แบ่งวงหลังจากค้นหารายการ
Habib

คำตอบ:


193

คุณควรใช้ Linq ได้ที่นี่:

var matchingvalues = myList
    .Where(stringToCheck => stringToCheck.Contains(myString));

หากคุณเพียงต้องการส่งคืนรายการแรกที่ตรงกัน:

var match = myList
    .FirstOrDefault(stringToCheck => stringToCheck.Contains(myString));

if(match != null)
    //Do stuff

+1 - หรือแทนที่Whereด้วยFirstOrDefaultในกรณีที่สองของคุณmyList.FirstOrDefault(stringToCheck => stringToCheck.Contains(myString))
Habib

คำตอบที่ดี เพิ่งออกมาจากความอยากรู้ แต่: ทำไมมันถึงmatchingเป็นตัวกำหนดคอมไพเลอร์ ( var)? เนื่องจากฉันรู้ว่ารายการของฉันเป็นประเภทStringมันจะปลอดภัยที่จะใช้string matchingในกรณีนี้หรือไม่
Dimitris Iliadis

1
@JimIliadis "var" และ "สตริง" หมายถึงสิ่งเดียวกันในกรณีนี้ - คอมไพเลอร์สมาร์ทก็พอจะรู้ว่าผลที่ได้สามารถเพียงเป็น 'สตริง' var เป็นจริงเพียงสิ่งที่รูปแบบการเข้ารหัส (เมื่อไม่ได้ใช้ชนิดที่ไม่ระบุชื่อ)
เดฟนัง

แสดงความคิดเห็นในเธรดที่เก่าเกินไป แต่พบข้อยกเว้นหนึ่งประการ เมื่อคุณใช้ firstordefault () ตรวจสอบให้แน่ใจว่าสามารถคืนค่าเริ่มต้นได้เช่นกัน ดังนั้นสมมติว่าคุณกำลังส่งสตริง empy เช่น mystring = "" และคุณคาดหวังว่าจะไม่มีอะไรแสดง แต่ก็ยังจะแสดงรายการแรกของรายการเพราะคุณได้เลือกรหัสผ่านแรก
นักพัฒนาสกปรก

@DirtyDeveloper ไม่แน่ใจว่าสิ่งที่คุณหมายถึง - ตัวอย่างของคุณจะกลับ 'null ถ้าไม่มีสตริงว่างในรายการเป้าหมาย คุณพูดถูกถ้าคุณพยายามจะใช้ FirstOrDefault () กับประเภท struct เช่น List <int> - FirstOrDefault () จะคืนค่า '0' และไม่ใช่ null - อย่างไรก็ตามคำถามนี้เกี่ยวกับสตริงโดยเฉพาะ
Dave Bish

29

คำตอบพื้นฐานคือคุณต้องวนซ้ำวนซ้ำและตรวจสอบองค์ประกอบใด ๆ ที่มีสตริงที่ระบุ ดังนั้นสมมติว่ารหัสคือ:

foreach(string item in myList)
{
    if(item.Contains(myString))
       return item;
}

โค้ดที่เทียบเท่า แต่สั้น ๆ คือ:

mylist.Where(x => x.Contains(myString)).FirstOrDefault();

ที่นี่ x คือพารามิเตอร์ที่ทำหน้าที่เหมือน "รายการ" ในรหัสด้านบน



9
for (int i = 0; i < myList.Length; i++)
{
    if (myList[i].Contains(myString)) // (you use the word "contains". either equals or indexof might be appropriate)
    {
        return i;
    }
}

ลูปแบบเก่ามักจะเร็วที่สุด


ตั้งแต่ฉันไปเพื่อประสิทธิภาพคุณแนะนำว่าวิธีนี้เร็วขึ้น (ดังนั้นมีประสิทธิภาพมากขึ้น)?
Dimitris Iliadis

2
ฉันยังไม่ได้ทดสอบอย่างสมบูรณ์ แต่ฉันเดาว่ามันจะเร็วขึ้น ต้องผ่านหนึ่งรายการเท่านั้นจนกว่าจะพบบางสิ่งและแตกตัวเร็ว (เช่นตัวเลือก Linq อาจทำได้ถ้าเขียนได้ดี) ไม่มีวิธีการเรียกใช้ค่าโสหุ้ยของ linq หรือค่าใช้จ่าย lambda ของ linq เช่นกัน ไม่ใช่ว่าสิ่งเหล่านี้เป็นสาเหตุของความกังวลอย่างมาก แต่อาจทำให้ประสิทธิภาพในการทำงานลดลง
แมคเคย์

ทำไมไม่ใช้ List.Equals ()
F8ER

@ V.7 เพราะเขาเพียงต้องการที่จะรู้ว่ารายการหนึ่งในรายการที่มีสตริงย่อย list.equals ไม่ใช่เครื่องมือที่ถูกต้องสำหรับงาน ["abc", "def", "ghi"] ไม่มี "hi" ในแบบที่ OP อธิบาย list.equals ไม่ได้ใช้ประเภทข้อมูลที่ถูกต้อง
แมคเคย์

6

หากคุณต้องการรายการของสตริงที่มีสตริงของคุณ:

var newList = myList.Where(x => x.Contains(myString)).ToList();

ตัวเลือกอื่นคือใช้ Linq FirstOrDefault

var element = myList.Where(x => x.Contains(myString)).FirstOrDefault();

โปรดทราบว่าContainsวิธีการใช้ตัวพิมพ์เล็กและใหญ่


1
เตือนความจำดีเกี่ยวกับตัวพิมพ์เล็กและตัวพิมพ์ใหญ่ใช้ StringComparison.InvariantCultureIgnoreCase
JoshYates1980

2

คุณสามารถใช้FirstOrDefaultวิธีการขยายของ Linq :

string element = myList.FirstOrDefault(s => s.Contains(myString));

สิ่งนี้จะส่งคืนองค์ประกอบกำปั้นที่ประกอบด้วยสตริงย่อยmyStringหรือnullหากไม่พบองค์ประกอบดังกล่าว

ถ้าสิ่งที่คุณต้องการคือดัชนีใช้เมธอดList<T>ของคลาสFindIndex:

int index = myList.FindIndex(s => s.Contains(myString));

นี่จะส่งคืนดัชนีขององค์ประกอบกำปั้นที่มีสตริงย่อยmyStringหรือ-1หากไม่พบองค์ประกอบดังกล่าว


2

คำตอบที่ดีมากมายที่นี่ แต่ฉันใช้แบบง่าย ๆ โดยใช้Existsดังต่อไปนี้:

foreach (var setting in FullList)
{
    if(cleanList.Exists(x => x.ProcedureName == setting.ProcedureName)) 
       setting.IsActive = true; // do you business logic here 
    else
       setting.IsActive = false;
    updateList.Add(setting);
}

2

คุณควรจะใช้อะไรแบบนี้มันใช้ได้ผลกับฉัน:

var valuesToMatch = yourList.Where(stringCheck => stringCheck.Contains(myString));

หรืออะไรทำนองนี้ถ้าคุณต้องการดูว่ามันไม่ตรง

 var valuesToMatch = yourList.Where(stringCheck => !stringCheck.Contains(myString));

1

คุณสามารถใช้ได้

var match=myList.Where(item=>item.Contains("Required String"));
foreach(var i in match)
{
//do something with the matched items
}

LINQ มอบความสามารถในการ "สืบค้น" การรวบรวมข้อมูลใด ๆ คุณสามารถใช้ไวยากรณ์เช่นแบบสอบถามฐานข้อมูล (เลือกที่ ฯลฯ ) ในคอลเลกชัน (นี่คือการรวบรวม (รายการ) ของสตริง)

ดังนั้นคุณกำลังทำเช่น "รับฉันรายการจากรายการที่เป็นไปตามเงื่อนไขที่กำหนด"

ข้างในจุดที่คุณใช้ "แลมบ์ดานิพจน์"

ที่จะบอกว่าการแสดงออกแลมบ์ดาสั้น ๆ เป็นสิ่งที่ต้องการ (พารามิเตอร์อินพุต => ค่าส่งคืน)

ดังนั้นสำหรับพารามิเตอร์ "item" จะส่งคืน "item.Contains (" สตริงที่จำเป็น ")" ดังนั้นมันจะคืนจริงถ้ารายการมีสตริงและดังนั้นจึงได้รับเลือกจากรายการเนื่องจากมันเป็นไปตามเงื่อนไข


1

เพื่อให้ง่ายใช้สิ่งนี้;

foreach(string item in myList)//Iterate through each item.
{
 if(item.Contains("Search Term")//True if the item contains search pattern.
 {
   return item;//Return the matched item.
 }
}

อีกวิธีหนึ่งในการทำเช่นนี้กับ for loop ใช้สิ่งนี้;

    for (int iterator = 0; iterator < myList.Count; iterator++)
    {
        if (myList[iterator].Contains("String Pattern"))
        {
            return myList[iterator];
        }
    }

เพียงแค่ชี้ให้เห็นว่าคุณพลาดวงเล็บปิดออกหนึ่งบรรทัดของรหัส .. ถ้า (item.Contains ("คำค้นหา"))
Alex

0

ฉันไม่เห็นตัวเลือกบูลในคำตอบอื่น ๆ ดังนั้นฉันหวังว่ารหัสด้านล่างจะช่วยให้ใครบางคน

เพียงแค่ใช้ Any()

string myString = "test";
bool exists = myList
             .Where(w => w.COLUMN_TO_CHECK.Contains(myString)).Any();

0

มันเป็นไปได้ที่จะรวมใด ๆ ที่ไหนก่อนและ FirstOrDefault; หรือเพียงแค่วางภาคแสดงในวิธีการเหล่านั้นขึ้นอยู่กับสิ่งที่จำเป็น

คุณควรหลีกเลี่ยงการใช้อันดับแรกยกเว้นว่าคุณต้องการให้เกิดข้อยกเว้นเมื่อไม่พบข้อมูลที่ตรงกัน FirstOrDefault มักจะเป็นตัวเลือกที่ดีกว่าตราบใดที่คุณรู้ว่ามันจะคืนค่าเริ่มต้นของประเภทหากไม่พบการจับคู่ (ค่าเริ่มต้นของสตริงเป็นโมฆะ int คือ 0, บูลเป็นเท็จ ฯลฯ )

using System.Collections.Generic;
using System.Linq;


bool exists;
string firstMatch;
IEnumerable<string> matchingList;

var myList = new List<string>() { "foo", "bar", "foobar" };

exists = myList.Any(x => x.Contains("o"));
// exists => true

firstMatch = myList.FirstOrDefault(x => x.Contains("o"));
firstMatch = myList.First(x => x.Contains("o"));
// firstMatch => "foo"

firstMatch = myList.First(x => x.Contains("dark side"));
// throws exception because no element contains "dark side"

firstMatch = myList.FirstOrDefault(x => x.Contains("dark side"));
// firstMatch => null

matchingList = myList.Where(x => x.Contains("o")); 
// matchingList => { "foo", "foobar" }

ทดสอบรหัสนี้ @ https://rextester.com/TXDL57489

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