ฉันมีString[]
ค่าด้วยเช่น:
public static final String[] VALUES = new String[] {"AB","BC","CD","AE"};
ที่กำหนดString s
จะมีวิธีที่ดีของการทดสอบว่าVALUES
มีs
?
ฉันมีString[]
ค่าด้วยเช่น:
public static final String[] VALUES = new String[] {"AB","BC","CD","AE"};
ที่กำหนดString s
จะมีวิธีที่ดีของการทดสอบว่าVALUES
มีs
?
คำตอบ:
Arrays.asList(yourArray).contains(yourValue)
คำเตือน: วิธีนี้ใช้ไม่ได้กับอาร์เรย์ของดั้งเดิม (ดูความคิดเห็น)
String[] values = {"AB","BC","CD","AE"};
boolean contains = Arrays.stream(values).anyMatch("s"::equals);
เพื่อตรวจสอบว่าอาร์เรย์ของint
, double
หรือlong
มีการใช้งานที่คุ้มค่าIntStream
, DoubleStream
หรือLongStream
ตามลำดับ
int[] a = {1,2,3,4};
boolean contains = IntStream.of(a).anyMatch(x -> x == 4);
ArrayList
แต่ไม่ได้java.util.ArrayList
ตามที่คุณคาดหวังชั้นจริงกลับคือ: หมายถึง:java.util.Arrays.ArrayList<E>
public class java.util.Arrays {private static class ArrayList<E> ... {}}
อาร์เรย์อ้างอิงไม่ดี สำหรับกรณีนี้เราอยู่หลังชุด ตั้งแต่ Java SE 9 Set.of
เรามี
private static final Set<String> VALUES = Set.of(
"AB","BC","CD","AE"
);
"สตริงของ s มีวิธีทดสอบที่ดีหรือไม่ว่า VALUES มี s หรือไม่"
VALUES.contains(s)
O (1)
ประเภทสิทธิ , ไม่เปลี่ยนรูป , O (1)และรัดกุม สวย.*
เพียงเพื่อล้างรหัสขึ้นเพื่อเริ่มต้นด้วย เรามี (แก้ไข):
public static final String[] VALUES = new String[] {"AB","BC","CD","AE"};
นี่เป็นค่าคงที่ที่เปลี่ยนแปลงไม่ได้ซึ่ง FindBugs จะบอกคุณว่าซนมาก อย่าปรับเปลี่ยนสถิตศาสตร์และไม่อนุญาตให้ใช้รหัสอื่นเช่นกัน อย่างน้อยที่สุดฟิลด์ควรเป็นแบบส่วนตัว:
private static final String[] VALUES = new String[] {"AB","BC","CD","AE"};
(หมายเหตุคุณสามารถวางnew String[];
บิตได้)
อาร์เรย์อ้างอิงยังคงไม่ดีและเราต้องการชุด:
private static final Set<String> VALUES = new HashSet<String>(Arrays.asList(
new String[] {"AB","BC","CD","AE"}
));
(คนหวาดระแวงเช่นตัวฉันเองอาจรู้สึกสบายใจมากขึ้นถ้าถูกห่อไว้Collections.unmodifiableSet
- มันอาจถูกเปิดเผยสู่สาธารณะได้)
(* หากต้องการเพิ่มแบรนด์อีกเล็กน้อยคอลเลกชัน API ก็ยังคาดเดาได้ว่ายังไม่มีประเภทคอลเลกชันที่ไม่เปลี่ยนรูปแบบและไวยากรณ์ยังคงละเอียดเกินไปสำหรับรสนิยมของฉัน)
Arrays.asList
)
TreeSet
s ถูกปรับอัตราส่วนเพื่อให้จำนวนค่าเฉลี่ยขององค์ประกอบในที่เก็บข้อมูลเป็นค่าคงที่ประมาณ อย่างน้อยสำหรับอาร์เรย์สูงสุด 2 ^ 30 อาจมีผลกระทบจากการพูดแคชฮาร์ดแวร์ซึ่งการวิเคราะห์ big-O จะถูกละเว้น ยังถือว่าฟังก์ชันแฮชทำงานได้อย่างมีประสิทธิภาพ O(log n)
HashSet
คุณสามารถใช้ArrayUtils.contains
จากApache Commons Lang
public static boolean contains(Object[] array, Object objectToFind)
โปรดทราบว่าวิธีการนี้ผลตอบแทนถ้าอาร์เรย์ผ่านคือfalse
null
นอกจากนี้ยังมีวิธีการสำหรับอาร์เรย์ดั้งเดิมทุกชนิด
String[] fieldsToInclude = { "id", "name", "location" };
if ( ArrayUtils.contains( fieldsToInclude, "id" ) ) {
// Do some stuff.
}
เพียงใช้งานด้วยมือ:
public static <T> boolean contains(final T[] array, final T v) {
for (final T e : array)
if (e == v || v != null && v.equals(e))
return true;
return false;
}
ปรับปรุง:
v != null
สภาพเป็นค่าคงที่ภายในวิธีการ มันจะประเมินค่าบูลีนเดียวกันเสมอระหว่างการเรียกใช้เมธอด ดังนั้นหากอินพุตarray
มีขนาดใหญ่จะมีประสิทธิภาพมากกว่าในการประเมินเงื่อนไขนี้เพียงครั้งเดียวและเราสามารถใช้เงื่อนไขที่ง่ายขึ้น / เร็วขึ้นภายในfor
ลูปตามผลลัพธ์ contains()
วิธีการปรับปรุง:
public static <T> boolean contains2(final T[] array, final T v) {
if (v == null) {
for (final T e : array)
if (e == null)
return true;
}
else {
for (final T e : array)
if (e == v || v.equals(e))
return true;
}
return false;
}
Collection.contains(Object)
Arrays
และปรากฎว่านี้ไม่จำเป็นต้องเร็วกว่ารุ่นโดยใช้ArrayList
Arrays.asList(...).contains(...)
ค่าโสหุ้ยในการสร้างมีArrayList
ขนาดเล็กมากและArrayList.contains()
ใช้การวนซ้ำอย่างชาญฉลาด
สี่วิธีที่แตกต่างในการตรวจสอบว่าอาร์เรย์มีค่าหรือไม่
1) การใช้รายการ:
public static boolean useList(String[] arr, String targetValue) {
return Arrays.asList(arr).contains(targetValue);
}
2) ใช้ชุด:
public static boolean useSet(String[] arr, String targetValue) {
Set<String> set = new HashSet<String>(Arrays.asList(arr));
return set.contains(targetValue);
}
3) ใช้การวนรอบอย่างง่าย:
public static boolean useLoop(String[] arr, String targetValue) {
for (String s: arr) {
if (s.equals(targetValue))
return true;
}
return false;
}
4) การใช้ Arrays.binarySearch ():
รหัสด้านล่างไม่ถูกต้องมีการระบุไว้ที่นี่เพื่อความสมบูรณ์ binarySearch () สามารถใช้ได้กับอาร์เรย์ที่เรียงลำดับเท่านั้น คุณจะพบผลลัพธ์ที่ประหลาดด้านล่าง นี่เป็นตัวเลือกที่ดีที่สุดเมื่อเรียงลำดับแล้ว
public static boolean binarySearch(String[] arr, String targetValue) {
int a = Arrays.binarySearch(arr, targetValue);
return a > 0;
}
String testValue="test";
String newValueNotInList="newValue";
String[] valueArray = { "this", "is", "java" , "test" };
Arrays.asList(valueArray).contains(testValue); // returns true
Arrays.asList(valueArray).contains(newValueNotInList); // returns false
หากอาร์เรย์ไม่ได้ถูกจัดเรียงคุณจะต้องวนซ้ำทุกอย่างและทำการเรียกให้เท่ากับแต่ละตัว
หากมีการเรียงลำดับอาร์เรย์คุณสามารถทำการค้นหาแบบไบนารีซึ่งมีอยู่ในอาร์เรย์คลาส
โดยทั่วไปถ้าคุณจะทำการตรวจสอบสมาชิกจำนวนมากคุณอาจต้องการเก็บทุกอย่างไว้ในชุดไม่ใช่ในอาร์เรย์
สำหรับสิ่งที่คุ้มค่าฉันได้ทำการทดสอบเปรียบเทียบข้อเสนอแนะ 3 ข้อสำหรับความเร็ว ฉันสร้างจำนวนเต็มแบบสุ่มแปลงเป็นสตริงและเพิ่มเข้าไปในอาร์เรย์ ฉันค้นหาหมายเลข / สตริงที่เป็นไปได้สูงสุดซึ่งจะเป็นสถานการณ์กรณีที่เลวร้ายที่สุดสำหรับasList().contains()
สตริงสูงสุดซึ่งจะเป็นสถานการณ์กรณีที่เลวร้ายสำหรับ
เมื่อใช้ขนาดอาร์เรย์ 10K ผลลัพธ์คือ:
จัดเรียงและค้นหา: 15 การค้นหาแบบไบนารี: 0 asList.contain: 0
เมื่อใช้อาร์เรย์ 100K ผลลัพธ์คือ:
จัดเรียงและค้นหา: 156 การค้นหาแบบไบนารี: 0 asList.contain: 32
ดังนั้นหากอาร์เรย์ถูกสร้างขึ้นตามลำดับการเรียงลำดับการค้นหาแบบไบนารีจะเร็วที่สุดมิฉะนั้นasList().contains
จะเป็นวิธีที่จะไป หากคุณมีการค้นหาจำนวนมากมันอาจคุ้มค่าที่จะจัดเรียงอาร์เรย์เพื่อให้คุณสามารถใช้การค้นหาแบบไบนารี ทุกอย่างขึ้นอยู่กับใบสมัครของคุณ
ฉันคิดว่านี่เป็นผลลัพธ์ที่คนส่วนใหญ่คาดหวัง นี่คือรหัสทดสอบ:
import java.util.*;
public class Test
{
public static void main(String args[])
{
long start = 0;
int size = 100000;
String[] strings = new String[size];
Random random = new Random();
for (int i = 0; i < size; i++)
strings[i] = "" + random.nextInt( size );
start = System.currentTimeMillis();
Arrays.sort(strings);
System.out.println(Arrays.binarySearch(strings, "" + (size - 1) ));
System.out.println("Sort & Search : " + (System.currentTimeMillis() - start));
start = System.currentTimeMillis();
System.out.println(Arrays.binarySearch(strings, "" + (size - 1) ));
System.out.println("Search : " + (System.currentTimeMillis() - start));
start = System.currentTimeMillis();
System.out.println(Arrays.asList(strings).contains( "" + (size - 1) ));
System.out.println("Contains : " + (System.currentTimeMillis() - start));
}
}
แทนที่จะใช้ไวยากรณ์การกำหนดค่าเริ่มต้นด่วนของอาร์เรย์คุณก็สามารถกำหนดค่าเริ่มต้นเป็นรายการได้ทันทีในลักษณะที่คล้ายกันโดยใช้วิธี Arrays.asList เช่น:
public static final List<String> STRINGS = Arrays.asList("firstString", "secondString" ...., "lastString");
จากนั้นคุณสามารถทำได้ (เช่นด้านบน):
STRINGS.contains("the string you want to find");
ด้วย Java 8 คุณสามารถสร้างสตรีมและตรวจสอบว่ามีรายการใด ๆ ในสตรีมที่ตรงกัน"s"
:
String[] values = {"AB","BC","CD","AE"};
boolean sInArray = Arrays.stream(values).anyMatch("s"::equals);
หรือเป็นวิธีการทั่วไป:
public static <T> boolean arrayContains(T[] array, T value) {
return Arrays.stream(array).anyMatch(value::equals);
}
anyMatch
JavaDoc ระบุว่า"...May not evaluate the predicate on all elements if not necessary for determining the result."
ดังนั้นจึงอาจไม่จำเป็นต้องดำเนินการต่อหลังจากค้นหาคู่ที่ตรงกัน
คุณสามารถใช้คลาส Arraysเพื่อทำการค้นหาไบนารีสำหรับค่า ถ้าอาเรย์ของคุณไม่ได้ถูกจัดเรียงคุณจะต้องใช้ฟังก์ชั่นการเรียงลำดับในคลาสเดียวกันเพื่อเรียงลำดับอาเรย์แล้วค้นหามัน
ObStupidAnswer (แต่ฉันคิดว่ามีบทเรียนอยู่ที่นี่ที่อื่น):
enum Values {
AB, BC, CD, AE
}
try {
Values.valueOf(s);
return true;
} catch (IllegalArgumentException exc) {
return false;
}
ที่จริงแล้วถ้าคุณใช้ HashSet <String> ตามที่ Tom Hawtin เสนอให้คุณไม่ต้องกังวลเกี่ยวกับการเรียงลำดับและความเร็วของคุณก็เหมือนกับการค้นหาแบบไบนารีในอาร์เรย์ที่เรียงลำดับไว้ล่วงหน้าซึ่งอาจเร็วกว่า
ทุกอย่างขึ้นอยู่กับการตั้งค่ารหัสของคุณอย่างชัดเจน แต่จากที่ฉันยืนลำดับจะเป็น:
ในอาร์เรย์ที่ไม่เรียงลำดับ :
ในอาร์เรย์ที่เรียงลำดับ:
ดังนั้นทั้งสองวิธี HashSet สำหรับการชนะ
หากคุณมีห้องสมุด google collection คำตอบของ Tom สามารถทำให้ง่ายขึ้นได้มากมายโดยใช้ ImmutableSet (http://google-collections.googlecode.com/svn/trunk/javadoc/com/google/common/collect/ImmutableSet.html)
สิ่งนี้จะขจัดความยุ่งเหยิงจำนวนมากออกจากการเริ่มต้นที่เสนอ
private static final Set<String> VALUES = ImmutableSet.of("AB","BC","CD","AE");
ทางออกหนึ่งที่เป็นไปได้:
import java.util.Arrays;
import java.util.List;
public class ArrayContainsElement {
public static final List<String> VALUES = Arrays.asList("AB", "BC", "CD", "AE");
public static void main(String args[]) {
if (VALUES.contains("AB")) {
System.out.println("Contains");
} else {
System.out.println("Not contains");
}
}
}
นักพัฒนามักทำ:
Set<String> set = new HashSet<String>(Arrays.asList(arr));
return set.contains(targetValue);
โค้ดด้านบนใช้งานได้ แต่ไม่จำเป็นต้องแปลงรายการเพื่อตั้งค่าก่อน การแปลงรายการเป็นชุดต้องใช้เวลาเพิ่ม สามารถทำได้ง่ายเพียง:
Arrays.asList(arr).contains(targetValue);
หรือ
for(String s: arr){
if(s.equals(targetValue))
return true;
}
return false;
อันแรกสามารถอ่านได้มากกว่าอันที่สอง
การใช้การวนรอบแบบง่ายเป็นวิธีที่มีประสิทธิภาพที่สุดในการทำสิ่งนี้
boolean useLoop(String[] arr, String targetValue) {
for(String s: arr){
if(s.equals(targetValue))
return true;
}
return false;
}
ได้รับความอนุเคราะห์จากProgramcreek
ในJava 8ใช้ Streams
List<String> myList =
Arrays.asList("a1", "a2", "b1", "c2", "c1");
myList
.stream()
.filter(s -> s.startsWith("c"))
.map(String::toUpperCase)
.sorted()
.forEach(System.out::println);
สำหรับอาร์เรย์ที่มีความยาว จำกัด ให้ใช้ดังต่อไปนี้ (ตามที่กำหนดโดยcamickr ) สิ่งนี้ช้าสำหรับการตรวจสอบซ้ำโดยเฉพาะอย่างยิ่งสำหรับอาร์เรย์ที่ยาวกว่า (การค้นหาเชิงเส้น)
Arrays.asList(...).contains(...)
เพื่อประสิทธิภาพที่รวดเร็วหากคุณตรวจสอบองค์ประกอบที่ใหญ่กว่าซ้ำหลายครั้ง
อาร์เรย์เป็นโครงสร้างที่ไม่ถูกต้อง ใช้ a TreeSet
และเพิ่มแต่ละองค์ประกอบเข้าไป มันเรียงลำดับองค์ประกอบและมีexist()
วิธีที่รวดเร็ว(การค้นหาแบบไบนารี)
หากองค์ประกอบใช้Comparable
& คุณต้องการTreeSet
เรียงตาม:
ElementClass.compareTo()
ต้องใช้งานร่วมกับElementClass.equals()
: ดูTriads ที่ไม่แสดงเพื่อต่อสู้? (Java Set ไม่มีรายการ)
TreeSet myElements = new TreeSet();
// Do this for each element (implementing *Comparable*)
myElements.add(nextElement);
// *Alternatively*, if an array is forceably provided from other code:
myElements.addAll(Arrays.asList(myArray));
มิฉะนั้นให้ใช้ของคุณเองComparator
:
class MyComparator implements Comparator<ElementClass> {
int compareTo(ElementClass element1; ElementClass element2) {
// Your comparison of elements
// Should be consistent with object equality
}
boolean equals(Object otherComparator) {
// Your equality of comparators
}
}
// construct TreeSet with the comparator
TreeSet myElements = new TreeSet(new MyComparator());
// Do this for each element (implementing *Comparable*)
myElements.add(nextElement);
ผลตอบแทน: ตรวจสอบการมีอยู่ขององค์ประกอบบางอย่าง:
// Fast binary search through sorted elements (performance ~ log(size)):
boolean containsElement = myElements.exists(someElement);
TreeSet
? HashSet
เร็วกว่า (O (1)) และไม่ต้องการสั่งซื้อ
ลองสิ่งนี้:
ArrayList<Integer> arrlist = new ArrayList<Integer>(8);
// use add() method to add elements in the list
arrlist.add(20);
arrlist.add(25);
arrlist.add(10);
arrlist.add(15);
boolean retval = arrlist.contains(10);
if (retval == true) {
System.out.println("10 is contained in the list");
}
else {
System.out.println("10 is not contained in the list");
}
ใช้วิธีการต่อไปนี้ ( contains()
วิธีการที่อยู่ArrayUtils.in()
ในรหัสนี้):
ObjectUtils.java
public class ObjectUtils{
/**
* A null safe method to detect if two objects are equal.
* @param object1
* @param object2
* @return true if either both objects are null, or equal, else returns false.
*/
public static boolean equals(Object object1, Object object2){
return object1==null ? object2==null : object1.equals(object2);
}
}
ArrayUtils.java
public class ArrayUtils{
/**
* Find the index of of an object is in given array, starting from given inclusive index.
* @param ts Array to be searched in.
* @param t Object to be searched.
* @param start The index from where the search must start.
* @return Index of the given object in the array if it is there, else -1.
*/
public static <T> int indexOf(final T[] ts, final T t, int start){
for(int i = start; i < ts.length; ++i)
if(ObjectUtils.equals(ts[i], t))
return i;
return -1;
}
/**
* Find the index of of an object is in given array, starting from 0;
* @param ts Array to be searched in.
* @param t Object to be searched.
* @return indexOf(ts, t, 0)
*/
public static <T> int indexOf(final T[] ts, final T t){
return indexOf(ts, t, 0);
}
/**
* Detect if the given object is in the given array.
* @param ts Array to be searched in.
* @param t Object to be searched.
* @return If indexOf(ts, t) is greater than -1.
*/
public static <T> boolean in(final T[] ts, final T t){
return indexOf(ts, t) > -1 ;
}
}
ดังที่คุณเห็นในรหัสข้างต้นว่ามีวิธีการอรรถประโยชน์อื่น ๆObjectUtils.equals()
และArrayUtils.indexOf()
ที่ใช้ในสถานที่อื่นเช่นกัน
ตรวจสอบสิ่งนี้
String[] VALUES = new String[] {"AB","BC","CD","AE"};
String s;
for(int i=0; i< VALUES.length ; i++)
{
if ( VALUES[i].equals(s) )
{
// do your stuff
}
else{
//do your stuff
}
}
else
สำหรับทุกรายการที่ไม่ตรงกับ (ดังนั้นหากคุณกำลังมองหา "AB" ในอาร์เรย์นั้นก็จะไปที่นั่น 3 ครั้งตั้งแต่วันที่ 3 ของค่าไม่ได้ "AB ")
Arrays.asList () -> จากนั้นการเรียกเมธอด contain () จะใช้งานได้ตลอดเวลา แต่อัลกอริทึมการค้นหาดีกว่ามากเนื่องจากคุณไม่จำเป็นต้องสร้าง wrapper รายการที่มีน้ำหนักเบารอบ ๆ อาร์เรย์ซึ่งเป็นสิ่งที่ Arrays.asList () ทำ .
public boolean findString(String[] strings, String desired){
for (String str : strings){
if (desired.equals(str)) {
return true;
}
}
return false; //if we get here… there is no desired String, return false.
}
Arrays.asList
ไม่ใช่ O (n) มันเป็นเพียงเสื้อคลุมที่มีน้ำหนักเบา ลองดูที่การนำไปปฏิบัติ
หากคุณไม่ต้องการให้มันเป็นกรณี ๆ ไป
Arrays.stream(VALUES).anyMatch(s::equalsIgnoreCase);
ใช้Array.BinarySearch(array,obj)
สำหรับค้นหาวัตถุที่กำหนดในอาร์เรย์หรือไม่
ตัวอย่าง:
if (Array.BinarySearch(str, i) > -1)` → true --exists
false - ไม่มีอยู่
Array.BinarySearch
และArray.FindIndex
เป็นวิธีการ. NET และไม่มีอยู่ใน Java
The array must be sorted prior to making this call. If it is not sorted, the results are undefined.
สร้างบูลีนเริ่มแรกตั้งค่าเป็นเท็จ เรียกใช้การวนซ้ำเพื่อตรวจสอบค่าทุกค่าในอาร์เรย์และเปรียบเทียบกับค่าที่คุณกำลังตรวจสอบ หากคุณเคยได้รับการแข่งขันให้ตั้งค่าบูลีนเป็นจริงและหยุดการวนซ้ำ จากนั้นยืนยันว่าบูลีนเป็นจริง
ลองใช้วิธีการทดสอบเพรดิเคตของ Java 8
นี่คือตัวอย่างที่สมบูรณ์ของมัน
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
public class Test {
public static final List<String> VALUES = Arrays.asList("AA", "AB", "BC", "CD", "AE");
public static void main(String args[]) {
Predicate<String> containsLetterA = VALUES -> VALUES.contains("AB");
for (String i : VALUES) {
System.out.println(containsLetterA.test(i));
}
}
}
http://mytechnologythought.blogspot.com/2019/10/java-8-predicate-test-method-example.html
https://github.com/VipulGulhane1/java8/blob/master/Test.java
การใช้ a Spliterator
ป้องกันการสร้าง a ที่ไม่จำเป็น List
boolean found = false; // class variable
String search = "AB";
Spliterator<String> spl = Arrays.spliterator( VALUES, 0, VALUES.length );
while( (! found) && spl.tryAdvance(o -> found = o.equals( search )) );
found == true
ถ้าsearch
มีอยู่ในอาร์เรย์
มันใช้งานได้กับอาร์เรย์ดั้งเดิม
public static final int[] VALUES = new int[] {1, 2, 3, 4};
boolean found = false; // class variable
int search = 2;
Spliterator<Integer> spl = Arrays.spliterator( VALUES, 0, VALUES.length );
…
ขณะที่ฉันจัดการกับ Java ระดับต่ำโดยใช้ชนิดดั้งเดิมไบต์และไบต์ [] ดีที่สุดที่ฉันได้มาจากbytes-java https://github.com/patrickfav/bytes-javaดูเหมือนงานดี
คุณสามารถตรวจสอบได้สองวิธี
A) โดยการแปลงอาร์เรย์เป็นสตริงและจากนั้นตรวจสอบสตริงที่จำเป็นโดยวิธีการ
String a=Arrays.toString(VALUES);
System.out.println(a.contains("AB"));
System.out.println(a.contains("BC"));
System.out.println(a.contains("CD"));
System.out.println(a.contains("AE"));
B) นี่เป็นวิธีที่มีประสิทธิภาพมากกว่า
Scanner s=new Scanner(System.in);
String u=s.next();
boolean d=true;
for(int i=0;i<VAL.length;i++)
{
if(VAL[i].equals(u)==d)
System.out.println(VAL[i] +" "+u+VAL[i].equals(u));
}