มีเหตุผลหรือไม่
Lists.transform()
แต่ไม่มี
Lists.filter()
เหรอ?
ฉันจะกรองรายการให้ถูกต้องได้อย่างไร? ฉันสามารถใช้
new ArrayList(Collection2.filter())
แน่นอน แต่วิธีนี้ไม่รับประกันว่าการสั่งซื้อของฉันจะยังคงเหมือนเดิมถ้าฉันเข้าใจถูกต้อง
มีเหตุผลหรือไม่
Lists.transform()
แต่ไม่มี
Lists.filter()
เหรอ?
ฉันจะกรองรายการให้ถูกต้องได้อย่างไร? ฉันสามารถใช้
new ArrayList(Collection2.filter())
แน่นอน แต่วิธีนี้ไม่รับประกันว่าการสั่งซื้อของฉันจะยังคงเหมือนเดิมถ้าฉันเข้าใจถูกต้อง
List.newArrayList(Iterables.filter(...)) Lists.newArrayList(Iterables.filter(...))
คำตอบ:
ไม่ได้ใช้งานเนื่องจากจะแสดงวิธีการช้าจำนวนมากที่เป็นอันตรายเช่น #get (ดัชนี) ในมุมมองรายการที่ส่งคืน (ข้อบกพร่องด้านประสิทธิภาพที่เชิญชวน) และ ListIterator ก็จะต้องใช้ความเจ็บปวดเช่นกัน (แม้ว่าฉันจะส่งแพทช์เมื่อหลายปีก่อนเพื่อปกปิดสิ่งนั้น)
เนื่องจากวิธีการจัดทำดัชนีไม่สามารถมีประสิทธิภาพในมุมมองรายการที่กรองได้จึงควรใช้วิธีการกรองที่กรองได้ซึ่งไม่มี
filterหมายถึงมุมมองอย่างสม่ำเสมอ (พร้อมกับพฤติกรรมที่บ่งบอกเป็นนัยว่า) ไม่ว่าจะเป็นIterables.filterเช่นนั้นSets.filterเป็นต้นเนื่องจากIterables.filterรวมเข้ากับสิ่งcopyOfใด ๆได้อย่างง่ายดายImmutableCollectionฉันจึงพบว่านี่เป็นการแลกเปลี่ยนการออกแบบที่ดี (เทียบกับวิธีการและชื่อพิเศษเช่นfilteredCopyหรืออะไรก็ตามสำหรับการรวมยูทิลิตี้อย่างง่าย)
คุณสามารถใช้ได้Iterables.filterซึ่งจะรักษาการสั่งซื้ออย่างแน่นอน
โปรดทราบว่าด้วยการสร้างรายการใหม่คุณจะคัดลอกองค์ประกอบ (แน่นอนว่าเป็นเพียงการอ้างอิง) ดังนั้นจะไม่เป็นการดูสดในรายการเดิม การสร้างมุมมองจะค่อนข้างยุ่งยาก - พิจารณาสถานการณ์นี้:
Predicate<StringBuilder> predicate =
/* predicate returning whether the builder is empty */
List<StringBuilder> builders = Lists.newArrayList();
List<StringBuilder> view = Lists.filter(builders, predicate);
for (int i = 0; i < 10000; i++) {
builders.add(new StringBuilder());
}
builders.get(8000).append("bar");
StringBuilder firstNonEmpty = view.get(0);
นั่นจะต้องวนซ้ำรายการเดิมทั้งหมดโดยใช้ตัวกรองกับทุกอย่าง ฉันคิดว่าอาจต้องการให้การจับคู่เพรดิเคตไม่เปลี่ยนแปลงตลอดอายุการใช้งานของมุมมอง แต่นั่นจะไม่เป็นที่น่าพอใจทั้งหมด
(นี่เป็นเพียงการคาดเดาในใจคุณบางทีผู้ดูแลฝรั่งคนหนึ่งอาจจะชิปด้วยเหตุผลที่แท้จริง :)
Collections2.filter.iteratorเพียงแค่โทรIterables.filterดังนั้นผลลัพธ์ก็เหมือนกัน
Iterables.filterเวอร์ชันนี้เพื่อความชัดเจน
view.size()รหัสในภายหลัง :)
ฉันสามารถใช้ได้
new List(Collection2.filter())แน่นอน แต่วิธีนี้ไม่รับประกันว่าการสั่งซื้อของฉันจะยังคงเหมือนเดิม
นี่ไม่เป็นความจริง Collections2.filter()เป็นฟังก์ชันที่มีการประเมินอย่างเกียจคร้านซึ่งจะไม่กรองคอลเล็กชันของคุณจนกว่าคุณจะเริ่มเข้าถึงเวอร์ชันที่กรองแล้ว ตัวอย่างเช่นหากคุณวนซ้ำในเวอร์ชันที่กรองแล้วองค์ประกอบที่กรองแล้วจะปรากฏออกมาจากตัววนซ้ำตามลำดับเดียวกันกับคอลเล็กชันเดิมของคุณ (ลบด้วยสิ่งที่กรองออกอย่างเห็นได้ชัด)
บางทีคุณอาจคิดว่ามันทำหน้าที่กรองข้อมูลจากนั้นทิ้งผลลัพธ์ลงในคอลเลคชันบางรูปแบบโดยพลการและไม่มีการเรียงลำดับ แต่ก็ไม่ได้
ดังนั้นหากคุณใช้เอาต์พุตCollections2.filter()เป็นอินพุตไปยังรายการใหม่คำสั่งซื้อเดิมของคุณจะยังคงอยู่
การใช้การนำเข้าแบบคงที่ (และLists.newArrayListฟังก์ชัน) จะค่อนข้างรวบรัด:
List filteredList = newArrayList(filter(originalList, predicate));
โปรดทราบว่าในขณะที่Collections2.filterจะไม่กระหายย้ำกว่าคอลเลกชันพื้นฐานLists.newArrayList จะ - ArrayListมันจะดึงทุกองค์ประกอบของคอลเลกชันกรองและคัดลอกลงในใหม่
List filteredList = newArrayList(filter(originalList, new Predicate<T>() { @Override public boolean apply(T input) { return (...); } }));หรือ ie List filteredList = newArrayList(filter(originalList, Predicates.notNull()));
ดังที่จอนกล่าวไว้คุณสามารถใช้Iterables.filter(..)หรือCollections2.filter(..)และถ้าคุณไม่ต้องการมุมมองสดคุณสามารถใช้ImmutableList.copyOf(Iterables.filter(..))หรือLists.newArrayList( Iterables.filter(..))และการสั่งซื้อจะได้รับการดูแล
หากคุณสนใจในเหตุผลส่วนหนึ่งคุณสามารถไปที่https://github.com/google/guava/issues/505เพื่อดูรายละเอียดเพิ่มเติม
เมื่อสรุปสิ่งที่คนอื่นพูดคุณสามารถสร้าง Wrapper ทั่วไปเพื่อกรองรายการ:
public static <T> List<T> filter(Iterable<T> userLists, Predicate<T> predicate) {
return Lists.newArrayList(Iterables.filter(userLists, predicate));
}