การใช้. ใด ๆ () ในรายการ C # <> คืออะไร


40

ฉันได้คุยเรื่องนี้กับเพื่อนร่วมงานและเราไม่สามารถเข้าใจได้ว่าการใช้งานนั้นมีประโยชน์.AnyสำหรับอะไรList<>ใน C #

คุณสามารถตรวจสอบความถูกต้องขององค์ประกอบในอาร์เรย์เช่นคำสั่งต่อไปนี้:

if (MyList.Any()){ ...}  //Returns true or false

ซึ่งเป็นสิ่งเดียวกัน

if (MyList.Count() != 0) { ... }

และเป็นเรื่องธรรมดามากขึ้นอ่านได้และชัดเจนเกี่ยวกับเจตนาของifข้อความ

ในท้ายที่สุดเราติดอยู่กับความคิดนี้:

.Any() สามารถใช้งานได้เช่นกัน แต่ไม่ชัดเจนเกี่ยวกับเจตนาของโปรแกรมเมอร์และในกรณีนี้ไม่ควรใช้

แต่เรารู้สึกว่ามันไม่ถูกต้อง เราต้องคิดถึงบางสิ่ง

พวกเราคือ


40
มีเจตนาชัดเจนน้อยลงในด้านใด?
jk

35
ฉันท้าทายข้อเรียกร้องของคุณที่Any()ชัดเจนน้อยกว่า: Any()ชัดเจนกว่าสำหรับฉันโดยเฉพาะกับสภาพแลมบ์ดา การแปลรหัสเป็นภาษาอังกฤษในหัวของฉันif(MyList.Count(o => o > 10) > 0)กลายเป็น"จำนวนรายการมากกว่า 10 มากกว่า 0 หรือไม่" ในขณะที่if(MyList.Any(o => o > 10))กลายเป็น"มีรายการใดมากกว่า 10?"
BlueRaja - Danny Pflughoeft

3
@SargeBorsch - เฉพาะในกรณีที่คุณชอบการตั้งชื่อ Heskel / การทำงานซึ่งคนส่วนใหญ่ไม่ชอบ
Davor Ždralo

4
@ BlueRaja-DannyPflughoeft ฉันเห็นด้วย ฉันคิดว่ามีอะไรที่ชัดเจนกว่านี้เพราะมันจะกำจัดสิ่งที่อาจถือได้ว่าเป็นเลขอาถรรพ์
แอนดี้

2
@SargeBorsch: สร้าง SQL ขนานไปกับการมีAny Existsชื่อ Linq น่าจะเป็นแรงบันดาลใจมากกว่าโดย Haskell และ Python ซึ่งมีฟังก์ชั่นใด ๆ / ทั้งหมด
JacquesB

คำตอบ:


95

โปรดทราบว่าAnyไม่สามารถทำงานได้บนList; มันทำงานบนIEnumerableซึ่งหมายถึงประเภทที่เป็นรูปธรรมที่อาจมีหรือไม่มีCountคุณสมบัติ เป็นความจริงที่ว่ามันไม่จำเป็นต้องเป็นสิ่งที่ดีที่สุดที่จะใช้บน a Listแต่มันมีประโยชน์ในตอนท้ายของการสืบค้น LINQ Whereและมีประโยชน์มากขึ้นกว่ารุ่นแบบสแตนด์อโลนคือแทนที่ที่จะนำคำกริยาเช่นเดียวกับ ไม่มีอะไรในตัวListที่ทุกที่อยู่ใกล้สะดวกหรือแสดงออกเป็นAnyวิธีการขยาย

นอกจากนี้หากคุณกำลังใช้Count()(วิธีการขยาย LINQ สำหรับ IEnumerable) แทนที่จะเป็นCount(คุณสมบัติบนList) คุณจะต้องระบุลำดับทั้งหมดหากไม่สามารถปรับให้เหมาะสมได้โดยตรวจสอบว่าชนิดข้อมูลพื้นฐานของคุณมีCountคุณสมบัติ . หากคุณมีลำดับที่ยาวนานนี่อาจเป็นผลการปฏิบัติงานที่เห็นได้ชัดเจนเมื่อคุณไม่สนใจว่าการนับคืออะไรและต้องการทราบว่ามีรายการใดในคอลเลกชันหรือไม่


19
นี้. ประสิทธิภาพการทำงานด้านข้างAny()พร้อมกับภาคแสดงจะมีความหมายมากกว่าการเปรียบเทียบการแทนที่ของEnumerable.Count()ที่ใช้ภาคที่มี 0 :)
Dan Dan J

1
ฉันคิดว่านี่จะอธิบายพื้นฐานอย่างชัดเจนเพื่ออธิบายคำตอบที่ดีที่สุด
Tarik

2
IMHO ExistsมีความสะดวกสบายและมีความหมายเหมือนกับภาคAnyแสดง โดยใช้Count != 0สถานที่ให้บริการบนเป็นเรื่องปกติมากกว่าการใช้List Any()มันเป็นเพียงการตั้งค่าส่วนตัว ฉันได้ไปยังผ่านความพยายามของการเปลี่ยนแปลง_list_.Count()ไป_list_.Countในรหัสกลุ่มของฉัน มันสร้างความแตกต่างที่เห็นได้ชัดเจนสำหรับฉัน
Suncat2000

55

มีความแตกต่างเวลาทำงานCount()สามารถ O (n) โดยที่Any()O (1)


15
Count()จะไม่หยุดยั้งผู้ทำซ้ำที่ไม่มีที่สิ้นสุดในขณะที่Any()จะเพราะจะต้องโทรMoveNext()เพียงครั้งเดียว
Jon Purdy

3
รวบรัดและแม่นยำ แต่สิ่งนี้อ่านได้มากกว่าความคิดเห็นมากกว่าคำตอบ โปรแกรมเมอร์ชอบคำตอบที่เจาะลึกลงไปถึงสาเหตุ และการจัดให้มีคำอธิบาย พิจารณาแก้ไขคำตอบของคุณและขยายว่าทำไม O (1) อาจมีความสำคัญ

คำตอบที่ดีมากเพิ่งเรียนรู้ฉันควรใช้แทนการนับ == 0: d
MonsterMMORPG

4
Any(Func<T>)คือ O (n)
BlueRaja - Danny Pflughoeft

1
ในกรณีเฉพาะListประสิทธิภาพจะเหมือนกันเนื่องจากส่วนขยายใช้คุณสมบัติ เป็นจริงสำหรับคอลเลกชันทั้งหมดที่ใช้ICollectionอินเทอร์เฟซ
Thorkil Holm-Jacobsen

9

ที่จริงแล้วโปรดจำไว้ว่ามีคุณสมบัติList.Countและจากนั้นมีวิธีEnumerable.Count

ในตัวอย่างของคุณคุณกำลังใช้Enumerable.Count()เมธอดซึ่งต้องวนซ้ำทุก ๆ รายการของการแจงนับเพื่อส่งคืนผลลัพธ์ เห็นได้ชัดว่าช้ากว่าการโทรAny()ที่ต้องวนซ้ำไอเท็มแรกหากมีอยู่

แก้ไข:

ในการแสดงความคิดเห็นมันก็ชี้ให้เห็นอย่างถูกต้องเพื่อที่วิธีขยายไม่จำเป็นต้องย้ำผ่านรายการทั้งหมดถ้าตรวจพบว่านับยังเกิดขึ้นเป็นEnumerable.Count() ICollection<T>ดังนั้นในกรณีของ a การList<T>ใช้Countคุณสมบัติหรือเมธอดไม่ได้สร้างความแตกต่าง

IEnumerable.Countแหล่งที่มา:

public static int Count<TSource>(this IEnumerable<TSource> source) {
    if (source == null) throw Error.ArgumentNull("source");
    ICollection<TSource> collectionoft = source as ICollection<TSource>;
    if (collectionoft != null) return collectionoft.Count;
    ICollection collection = source as ICollection;
    if (collection != null) return collection.Count;
    int count = 0;
    using (IEnumerator<TSource> e = source.GetEnumerator()) {
        checked {
            while (e.MoveNext()) count++;
        }
    }
    return count;
}

ยุติธรรมพอสมควร แล้วการใช้คุณสมบัติ. Count แล้วล่ะ จะไม่ทำให้การอ่านเร็วขึ้นอย่างมีนัยสำคัญอาจเร็วหรือเร็วกว่าการโทรใด ๆ ()?
Gil Sand

4
ด้วยความList<T>แตกต่างของประสิทธิภาพจะเล็กน้อย ดังนั้นเพียงแค่ใช้สิ่งที่คุณต้องการ แต่สำหรับ IEnumerables ประเภทอื่น ๆ คุณจะได้รับเลือกระหว่างCount()(วิธีการ) Any()และในกรณีนั้นAny()จะเป็นผู้ชนะที่ชัดเจนสำหรับกรณีการใช้งานของคุณและควรเป็นที่ต้องการ สำหรับสิ่งที่คุ้มค่าฉันคิดว่าAny()ค่อนข้างอ่านง่ายและชัดเจน
sstan

@ สถานที่ใช่ใช่ถ้าหากสามารถนับจำนวนได้เพื่อทำการเปรียบเทียบมันจะสามารถปรับให้เหมาะสมและไม่เป็นไร
Esben Skov Pedersen

2
Count()มีความซับซ้อนเช่นเดียวCountกับICollections เนื่องจากวิธีการขยายนั้นใช้คุณสมบัติแทนการวนซ้ำ
Thorkil Holm-Jacobsen

ส่วนขยาย Linq ได้รับการปรับให้เหมาะสมสำหรับส่วนต่อประสานที่รู้จัก - IList, ICollection การอภิปรายเกี่ยวกับประสิทธิภาพที่นี่มีความซ้ำซ้อนโดยสิ้นเชิงแม้ว่าจะเป็นรายละเอียดการนำไปใช้งาน
ก็ตาม

6

คำถามที่น่าแปลกใจ - ฉันพบความตั้งใจที่จะเป็นที่ชัดเจนมากขึ้นกว่าเจตนาของlist.Any()list.Count()!=0

เจตนาหมายถึง: ถ้าคุณอ่านโค้ด someones (และคุณไม่ได้เขียนด้วยตัวเอง) มันชัดเจนหรือไม่ว่าโปรแกรมเมอร์ต้องการบรรลุอะไรและทำไมมันถึงเขียนเหมือนมัน หากปัญหาทั่วไปได้รับการแก้ไขอย่างซับซ้อนโดยไม่จำเป็นคุณจะต้องสงสัยทันทีและสงสัยว่าทำไมนักพัฒนาซอฟต์แวร์ไม่ได้ใช้วิธีที่ง่าย คุณดูรหัสและลองดูว่าคุณพลาดอะไรไปหรือเปล่า คุณกลัวที่จะเปลี่ยนรหัสเพราะคุณกังวลว่ามีผลข้างเคียงบางอย่างที่คุณหายไปและการเปลี่ยนแปลงอาจทำให้เกิดปัญหาที่ไม่คาดคิด

ความตั้งใจในการใช้Any()วิธีนี้ชัดเจนมาก - คุณต้องการทราบว่ามีองค์ประกอบใด ๆ ในรายการหรือไม่

เจตนาของการแสดงออกCount()!=0ในทางกลับกันไม่ชัดเจนสำหรับผู้อ่าน แน่นอนว่าไม่ใช่เรื่องยากที่จะเห็นว่านิพจน์บอกคุณว่ารายการนั้นว่างเปล่าหรือไม่ คำถามที่เกิดขึ้นเพราะคุณเขียนวิธีนี้โดยเฉพาะมากกว่าการใช้วิธีมาตรฐาน ทำไมคุณใช้Count()อย่างชัดเจน? หากคุณเพียงแค่ต้องรู้ว่ามีองค์ประกอบใด ๆในรายการทำไมคุณต้องการนับรายการทั้งหมดก่อน ทันทีที่คุณมาถึง 1 คุณจะได้รับคำตอบของคุณ หากแหล่งที่มาเป็นตัววนซ้ำในคอลเลกชันขนาดใหญ่ (อาจไม่มีที่สิ้นสุด) หรือถูกแปลเป็น SQL ก็อาจทำให้ประสิทธิภาพที่แตกต่างกันอย่างชาญฉลาด ดังนั้นบางทีการใช้ Count () อย่างชัดเจนคือการบังคับให้คิวรีแบบเลื่อนเวลาออกไปดำเนินการหรือสำรวจตัววนซ้ำ?

แต่แหล่งที่เป็นจริงList<T>ที่Count()เป็น O (1) และไม่มีผลข้างเคียง แต่ถ้ารหัสอาศัยคุณสมบัตินี้ของList<T>แล้วทำไมไม่ใช้Count-property ซึ่งระบุไว้อย่างชัดเจนว่าคุณคาดหวังการดำเนินการ O (1) โดยไม่มีผลข้างเคียง?

ตามที่เขียนไว้list.Count()!=0ทำสิ่งเดียวกันlist.Any()ยกเว้นยกเว้นมีความซับซ้อนมากขึ้นโดยไม่จำเป็นและเจตนาไม่ชัดเจน


ฉันอ่านทั้งสองอย่างว่า "รายการมีรายการใดบ้างหรือไม่" Count()มีการแปลงโดยนัยที่ฉันจะหลีกเลี่ยงการใช้ แต่ก็ไม่ชัดเจน คอมไพเลอร์อาจปรับให้เหมาะสมซึ่งจะทำให้การเข้ารหัสไม่สนใจเท่านั้น
Suncat2000

2

อาจจะเป็นเพียงคำว่า? Anyคำคุณศัพท์ไม่ได้พูดอะไรจริงๆ มาจาก Java ฉันจะเรียกมันว่าisNonEmptyมีกริยา ผู้ชาย SQL EXISTSอาจจะชอบ แต่อาจAnyเหมาะสมที่สุดในระบบ C #

เมื่อคุณคุ้นเคยกับมันแล้วมันจะต้องชัดเจนขึ้น คุณจะถาม " more than zeroเหลือขวดเบียร์ไหม" คุณคาดหวังว่าone or moreคนที่เริ่มนับพวกเขาก่อนที่พวกเขาตอบว่า "ไม่, ไม่มีany"?


1
ชื่อ "ใด ๆ " เข้าท่าเมื่อคุณคิดถึงมันในแง่ของ LINQ: Any()เป็นทางลัดจริงๆสำหรับAny(o => true)
BlueRaja - Danny Pflughoeft

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