ฉันจะตรวจสอบว่าอาร์เรย์มีค่าเฉพาะใน Java ได้อย่างไร


2276

ฉันมีString[]ค่าด้วยเช่น:

public static final String[] VALUES = new String[] {"AB","BC","CD","AE"};

ที่กำหนดString sจะมีวิธีที่ดีของการทดสอบว่าVALUESมีs?


5
ทางยาวรอบ ๆ มัน แต่คุณสามารถใช้สำหรับห่วง "สำหรับ (String s: VALUES) ถ้า (s.equals (" MYVALUE ")) กลับจริง;
แซค

70
@camickr สำหรับคำถามของคุณฉันตอบคำถามนี้และคำตอบของคุณเพราะคุณช่วยฉันในการเขียนโค้ด 30 นาทีและ 20 บรรทัดซึ่งน่าเกลียดสำหรับลูป --now- ไม่ได้อ่านเมื่อสามปีที่แล้ว (BTW ขอบคุณ :))
ติดตาม

3
@ camickr - ฉันมีสถานการณ์ที่เกือบจะเหมือนกันกับกรณีนี้: stackoverflow.com/a/223929/12943 มันเพิ่งได้รับการโหวต แต่เป็นเพียงสำเนา / วางจากเอกสารของดวงอาทิตย์ ฉันเดาว่าคะแนนขึ้นอยู่กับว่าคุณให้ความช่วยเหลือมากน้อยแค่ไหนและคุณพยายามลงคะแนนมากแค่ไหนและส่วนใหญ่คุณจะโพสต์เร็วแค่ไหน! บางทีเราอาจสะดุดความลับของ John Skeet! คำตอบที่ดี +1 สำหรับคุณ
Bill K

1
หากคุณใช้ Apache Commons ดังนั้นorg.apache.commons.lang.ArrayUtils.contain ()จะทำสิ่งนี้ให้คุณ
นายบอย

34
@camickr เพราะคนอย่างฉันคำถาม Google คลิกที่ผลลัพธ์ SO ดูคำตอบของคุณทดสอบใช้งานได้ตอบคำถามแล้วออกไป
Aequitas

คำตอบ:


2922
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);

87
ฉันค่อนข้างอยากรู้อยากเห็นเกี่ยวกับประสิทธิภาพการทำงานของนี้เมื่อเทียบกับฟังก์ชั่นการค้นหาในชั้นเรียนอาร์เรย์เมื่อเทียบกับอาร์เรย์และใช้ฟังก์ชั่นเท่ากับ () หรือ == สำหรับดั้งเดิม
โทมัส Owens

186
คุณจะไม่สูญเสียอะไรมากเพราะ asList () จะส่งกลับ ArrayList ที่มีอาร์เรย์อยู่ในใจ ตัวสร้างจะเปลี่ยนการอ้างอิงเพื่อที่จะไม่ต้องทำงานที่นั่นมากนัก และมี () / indexOf () จะทำซ้ำและใช้เท่ากับ () สำหรับพื้นฐานคุณควรจะดีกว่าการเข้ารหัสด้วยตัวคุณเองแม้ว่า สำหรับ Strings หรือคลาสอื่น ๆ จะไม่เห็นความแตกต่าง
Joey

18
แปลก NetBeans อ้างว่า 'Arrays.asList (วันหยุด)' สำหรับ 'int [] holidays' ส่งคืน 'list <int []>' และไม่ใช่ 'list <int>' มันมีเพียงองค์ประกอบเดียว ความหมายมีไม่ทำงานเพราะมันมีองค์ประกอบเดียว อาร์เรย์ int
Nyerguds

62
Nyerguds: จริง ๆ แล้วสิ่งนี้ไม่ได้ผลกับสิ่งดั้งเดิม ใน java primitive types ไม่สามารถเป็นแบบทั่วไปได้ asList ถูกประกาศเป็น <T> List <T> asList (T ... ) เมื่อคุณส่ง int [] ไปให้คอมไพเลอร์ infers T = int [] เพราะมันไม่สามารถอนุมานได้ว่า T = int เนื่องจาก primitives ไม่สามารถเป็นแบบทั่วไปได้
CromTheDestroyer

28
@Joey เพียงสังเกตด้านก็เป็นArrayListแต่ไม่ได้java.util.ArrayListตามที่คุณคาดหวังชั้นจริงกลับคือ: หมายถึง:java.util.Arrays.ArrayList<E> public class java.util.Arrays {private static class ArrayList<E> ... {}}
TWiStErRob

362

การอัพเดตที่กระชับสำหรับ Java SE 9

อาร์เรย์อ้างอิงไม่ดี สำหรับกรณีนี้เราอยู่หลังชุด ตั้งแต่ 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 ก็ยังคาดเดาได้ว่ายังไม่มีประเภทคอลเลกชันที่ไม่เปลี่ยนรูปแบบและไวยากรณ์ยังคงละเอียดเกินไปสำหรับรสนิยมของฉัน)


184
ยกเว้นมัน O (N) ในการสร้างคอลเลกชันในสถานที่แรก :)
Drew Noakes

61
ถ้าเป็นแบบคงที่คงต้องใช้หลายครั้ง ดังนั้นเวลาที่ใช้ในการเริ่มต้นชุดมีโอกาสที่จะค่อนข้างเล็กเมื่อเทียบกับค่าใช้จ่ายในการค้นหาเชิงเส้นจำนวนมาก
Xr

1
การสร้างคอลเลกชันจะถูกครอบงำโดยเวลาในการโหลดโค้ด (ซึ่งเป็นเทคนิค O (n) แต่คงที่ในทางปฏิบัติ)
Tom Hawtin - tackline

2
@ TomHawtin-tackline ทำไมคุณถึงพูดว่า "โดยเฉพาะที่นี่เราต้องการชุด"? ข้อดีของชุด (HashSet) ในกรณีนี้คืออะไร เหตุใด "อาร์เรย์อ้างอิง" จึงไม่ดี (โดย "อาร์เรย์อ้างอิง" หมายถึง ArrayList ที่สนับสนุนโดยอาร์เรย์ซึ่งสร้างโดยการเรียกไปยังArrays.asList)
Basil Bourque

6
@nmr จะเป็นTreeSet s ถูกปรับอัตราส่วนเพื่อให้จำนวนค่าเฉลี่ยขององค์ประกอบในที่เก็บข้อมูลเป็นค่าคงที่ประมาณ อย่างน้อยสำหรับอาร์เรย์สูงสุด 2 ^ 30 อาจมีผลกระทบจากการพูดแคชฮาร์ดแวร์ซึ่งการวิเคราะห์ big-O จะถูกละเว้น ยังถือว่าฟังก์ชันแฮชทำงานได้อย่างมีประสิทธิภาพ O(log n)HashSet
Tom Hawtin - tackline

206

คุณสามารถใช้ArrayUtils.containsจากApache Commons Lang

public static boolean contains(Object[] array, Object objectToFind)

โปรดทราบว่าวิธีการนี้ผลตอบแทนถ้าอาร์เรย์ผ่านคือfalsenull

นอกจากนี้ยังมีวิธีการสำหรับอาร์เรย์ดั้งเดิมทุกชนิด

ตัวอย่าง:

String[] fieldsToInclude = { "id", "name", "location" };

if ( ArrayUtils.contains( fieldsToInclude, "id" ) ) {
    // Do some stuff.
}

4
@ max4ever ฉันเห็นด้วย แต่นี่ก็ยังดีกว่า "กลิ้งของคุณเอง" และอ่านง่ายกว่าในแบบ raw raw
Jason

2

38
@ max4ever บางครั้งคุณมีห้องสมุดนี้รวมอยู่ด้วย (ด้วยเหตุผลอื่น ๆ ) และมันเป็นคำตอบที่ถูกต้องสมบูรณ์ ฉันกำลังมองหาสิ่งนี้อยู่แล้วและฉันต้องพึ่ง Apache Commons Lang ขอบคุณสำหรับคำตอบนี้
GuiSim

1
หรือคุณสามารถคัดลอกวิธี (และการพึ่งพาหากมี)
บัฟฟาโล่

10
@ max4ever แอป Android ส่วนใหญ่จะลดขนาดลงโดย Proguard ใส่เฉพาะคลาสและฟังก์ชั่นที่คุณต้องการลงในแอปของคุณ นั่นทำให้มันเท่ากับการม้วนของคุณเองหรือคัดลอกที่มาของสิ่ง apache และใครก็ตามที่ไม่ได้ใช้การทำให้เรียบง่ายนั้นไม่จำเป็นต้องบ่นประมาณ
700kb หรือ 78kb

158

เพียงใช้งานด้วยมือ:

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;
}

9
@Phoexo วิธีนี้เห็นได้ชัดว่าเร็วขึ้นเพราะคำตอบที่ได้รับการยอมรับจะนำอาเรย์ไปใส่ในรายการและเรียกใช้ method () ในรายการนั้นในขณะที่โซลูชันของฉันทำในสิ่งที่มี () เท่านั้น
icza

10
@AlastorMoody e == v ทำการตรวจสอบความเท่าเทียมกันของข้อมูลอ้างอิงซึ่งเร็วมาก หากวัตถุเดียวกัน (เหมือนกันโดยการอ้างอิง) อยู่ในอาร์เรย์มันจะพบได้เร็วขึ้น หากไม่ใช่อินสแตนซ์เดียวกันมันก็อาจจะยังคงเหมือนเดิมโดยอ้างว่าโดยวิธี equals () นี่คือสิ่งที่จะถูกตรวจสอบหากการอ้างอิงไม่เหมือนกัน
icza

20
ทำไมฟังค์ชั่นนี้ไม่ได้เป็นส่วนหนึ่งของ Java? ไม่น่าแปลกใจที่ผู้คนพูดว่า Java นั้นเต็มไปด้วยอารมณ์ ... ลองดูคำตอบทั้งหมดข้างต้นซึ่งใช้ไลบรารีหลาย ๆ อย่างเมื่อคุณต้องการเพียงแค่ลูป เด็กวันนี้!
phreakhead

4
@phreakhead มันเป็นส่วนหนึ่งของ Java ดูCollection.contains(Object)
Steve Kuo

11
@icza ถ้าคุณดูที่แหล่งที่มาของArraysและปรากฎว่านี้ไม่จำเป็นต้องเร็วกว่ารุ่นโดยใช้ArrayList Arrays.asList(...).contains(...)ค่าโสหุ้ยในการสร้างมีArrayListขนาดเล็กมากและArrayList.contains()ใช้การวนซ้ำอย่างชาญฉลาด
Axel

72

สี่วิธีที่แตกต่างในการตรวจสอบว่าอาร์เรย์มีค่าหรือไม่

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

5
ตัวอย่างการค้นหาแบบไบนารีของคุณควรส่งคืนค่า> 0;
จะ Sherwood

6
ทำไม? ฉันคิดว่ามันควรจะคืนค่า> -1 เนื่องจาก 0 จะแสดงว่ามันอยู่ที่ส่วนหัวของอาร์เรย์
mbelow

1
ตัวแปรแรกที่(a >= 0)ถูกต้องเพียงตรวจสอบเอกสารพวกเขาพูดว่า "โปรดทราบว่านี่เป็นการรับประกันว่าค่าส่งคืนจะเป็น> = 0 ถ้าหากพบกุญแจเท่านั้น"
Yoory N.

ทำไมจึงทำงานกับ String และไม่ต้อง int บูลีนสแตติกมีอยู่ (int [] ints, int k) {คืน arrays.asList (ints) .contain (k); }
Willians Martins

71

หากอาร์เรย์ไม่ได้ถูกจัดเรียงคุณจะต้องวนซ้ำทุกอย่างและทำการเรียกให้เท่ากับแต่ละตัว

หากมีการเรียงลำดับอาร์เรย์คุณสามารถทำการค้นหาแบบไบนารีซึ่งมีอยู่ในอาร์เรย์คลาส

โดยทั่วไปถ้าคุณจะทำการตรวจสอบสมาชิกจำนวนมากคุณอาจต้องการเก็บทุกอย่างไว้ในชุดไม่ใช่ในอาร์เรย์


1
เช่นเดียวกับที่ฉันพูดในคำตอบถ้าคุณใช้คลาส Arrays คุณสามารถเรียงลำดับอาร์เรย์จากนั้นทำการค้นหาแบบไบนารี่ในอาร์เรย์ที่เรียงลำดับใหม่
โทมัส Owens

1
@ โทมัส: ฉันเห็นด้วย หรือคุณสามารถเพิ่มทุกอย่างลงใน TreeSet ความซับซ้อนเดียวกัน ฉันจะใช้อาร์เรย์ถ้ามันไม่เปลี่ยนแปลง (อาจบันทึกสถานที่หน่วยความจำเล็กน้อยเนื่องจากการอ้างอิงอยู่อย่างต่อเนื่องแม้ว่าสตริงจะไม่) ฉันจะใช้ชุดหากสิ่งนี้จะเปลี่ยนแปลงตลอดเวลา
Uri

49

สำหรับสิ่งที่คุ้มค่าฉันได้ทำการทดสอบเปรียบเทียบข้อเสนอแนะ 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));
    }
}

6
ฉันไม่เข้าใจรหัสนี้ คุณเรียงลำดับ 'strings' ของอาเรย์และใช้อาเรย์ (เรียงลำดับ) เดียวกันในการเรียกทั้งสองไปยัง binarySearch จะแสดงสิ่งใดได้นอกจากการเพิ่มประสิทธิภาพรันไทม์ HotSpot เช่นเดียวกับการโทร asList.contain คุณสร้างรายการจากอาร์เรย์ที่เรียงลำดับแล้วมีอยู่ในนั้นด้วยค่าสูงสุด แน่นอนมันต้องใช้เวลา ความหมายของการทดสอบนี้คืออะไร? ไม่พูดถึงการเป็น microbenchmark เขียนไม่ถูกต้อง
เอริค

นอกจากนี้เนื่องจากการค้นหาแบบไบนารี่สามารถใช้กับชุดที่เรียงลำดับแล้วการเรียงลำดับและการค้นหาจึงเป็นวิธีเดียวที่จะใช้การค้นหาแบบไบนารี
Erik

การเรียงลำดับอาจกระทำไปแล้วด้วยเหตุผลอื่น ๆ อีกหลายประการเช่นสามารถเรียงลำดับบน init และไม่เคยเปลี่ยนแปลง มีใช้ในการทดสอบเวลาค้นหาด้วยตัวเอง ที่ซึ่งสิ่งนี้หล่นลงมา แต่ก็เป็นตัวอย่างที่ดีกว่าของการทำเครื่องหมายขนาดเล็ก Microbenchmarks เป็นเรื่องยากที่จะทำให้ถูกต้องใน Java และตัวอย่างเช่นควรดำเนินการทดสอบรหัสเพียงพอที่จะได้รับการเพิ่มประสิทธิภาพฮอตสปอตก่อนที่จะเรียกใช้การทดสอบจริงให้ใช้รหัสการทดสอบจริงมากกว่าคนเดียวด้วยตัวจับเวลา ตัวอย่างข้อผิดพลาด
Thor84no

7
การทดสอบนี้มีข้อบกพร่องขณะที่รันการทดสอบทั้ง 3 รายการในอินสแตนซ์ JVM เดียวกัน การทดสอบในภายหลังจะได้ประโยชน์จากการทดสอบก่อนหน้านี้ทำให้แคช JIT ฯลฯ
Steve Kuo

4
การทดสอบนี้ไม่เกี่ยวข้องจริงทั้งหมด การเรียงลำดับและการค้นหามีความซับซ้อนเป็นเส้นตรง (n * log (n)) ความซับซ้อนการค้นหาแบบไบนารีเป็นแบบลอการิทึมและ ArrayUtils.contain มีลักษณะเป็นเส้นตรง ไม่มีประโยชน์ในการเปรียบเทียบโซลูชันนี้เนื่องจากอยู่ในคลาสความซับซ้อนที่แตกต่างกันโดยสิ้นเชิง
dragn

37

แทนที่จะใช้ไวยากรณ์การกำหนดค่าเริ่มต้นด่วนของอาร์เรย์คุณก็สามารถกำหนดค่าเริ่มต้นเป็นรายการได้ทันทีในลักษณะที่คล้ายกันโดยใช้วิธี Arrays.asList เช่น:

public static final List<String> STRINGS = Arrays.asList("firstString", "secondString" ...., "lastString");

จากนั้นคุณสามารถทำได้ (เช่นด้านบน):

STRINGS.contains("the string you want to find");

35

ด้วย 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);
}

3
มันมีค่าที่จะต้องทราบถึงความเชี่ยวชาญดั้งเดิม
skiwi

หากต้องการเพิ่มanyMatchJavaDoc ระบุว่า"...May not evaluate the predicate on all elements if not necessary for determining the result."ดังนั้นจึงอาจไม่จำเป็นต้องดำเนินการต่อหลังจากค้นหาคู่ที่ตรงกัน
mkobit

28

คุณสามารถใช้คลาส Arraysเพื่อทำการค้นหาไบนารีสำหรับค่า ถ้าอาเรย์ของคุณไม่ได้ถูกจัดเรียงคุณจะต้องใช้ฟังก์ชั่นการเรียงลำดับในคลาสเดียวกันเพื่อเรียงลำดับอาเรย์แล้วค้นหามัน


คุณสามารถใช้ฟังก์ชั่นการเรียงลำดับในชั้นเรียนเดียวกันเพื่อให้บรรลุว่า ... ฉันควรเพิ่มเข้าไปในคำตอบของฉัน
โธมัสโอเวนส์

1
อาจมีค่าใช้จ่ายมากกว่าวิธี asList (). contain () ดังนั้นฉันคิดว่า เว้นแต่คุณจะต้องทำการตรวจสอบบ่อยครั้งมาก (แต่ถ้าเป็นเพียงรายการค่าคงที่ที่สามารถเรียงลำดับเพื่อเริ่มต้นให้ยุติธรรม)
Joey

จริง มีตัวแปรมากมายที่จะมีประสิทธิภาพมากที่สุด มันดีที่มีตัวเลือก
โทมัส Owens

รหัสบางส่วนที่ทำสิ่งนี้ที่นี่: stackoverflow.com/a/48242328/9131078
OOBalance

การเรียงลำดับอาร์เรย์ทั้งหมดเพื่อวัตถุประสงค์ในการค้นหามีราคาแพง เราสามารถใช้เวลา CPU เดียวกันสำหรับการค้นหาซับได้ ฉันชอบการค้นหาแบบไบนารี่ในคอลเล็กชั่นที่สร้างไว้แล้วเรียงตามลำดับก่อนหน้า
อรุณวิทย์

17

ObStupidAnswer (แต่ฉันคิดว่ามีบทเรียนอยู่ที่นี่ที่อื่น):

enum Values {
    AB, BC, CD, AE
}

try {
    Values.valueOf(s);
    return true;
} catch (IllegalArgumentException exc) {
    return false;
}

1
เห็นได้ชัดว่าการขว้างข้อยกเว้นมีน้ำหนักมาก แต่นี่จะเป็นวิธีใหม่ในการทดสอบค่าหากใช้งานได้ ข้อเสียคือต้องกำหนด enum ไว้ล่วงหน้า
James P.

13

ที่จริงแล้วถ้าคุณใช้ HashSet <String> ตามที่ Tom Hawtin เสนอให้คุณไม่ต้องกังวลเกี่ยวกับการเรียงลำดับและความเร็วของคุณก็เหมือนกับการค้นหาแบบไบนารีในอาร์เรย์ที่เรียงลำดับไว้ล่วงหน้าซึ่งอาจเร็วกว่า

ทุกอย่างขึ้นอยู่กับการตั้งค่ารหัสของคุณอย่างชัดเจน แต่จากที่ฉันยืนลำดับจะเป็น:

ในอาร์เรย์ที่ไม่เรียงลำดับ :

  1. HashSet
  2. asList
  3. จัดเรียง & ไบนารี

ในอาร์เรย์ที่เรียงลำดับ:

  1. HashSet
  2. ไบนารี่
  3. asList

ดังนั้นทั้งสองวิธี HashSet สำหรับการชนะ


2
สมาชิก HashSet ควรเป็น O (1) และการค้นหาแบบไบนารีในคอลเลกชันที่เรียงเป็น O (log n)
Skylar Saveland

11

หากคุณมีห้องสมุด 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");

10

ทางออกหนึ่งที่เป็นไปได้:

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");
      }
  }
}

8

นักพัฒนามักทำ:

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;

อันแรกสามารถอ่านได้มากกว่าอันที่สอง


7

การใช้การวนรอบแบบง่ายเป็นวิธีที่มีประสิทธิภาพที่สุดในการทำสิ่งนี้

boolean useLoop(String[] arr, String targetValue) {
    for(String s: arr){
        if(s.equals(targetValue))
            return true;
    }
    return false;
}

ได้รับความอนุเคราะห์จากProgramcreek


นี้จะโยนข้อยกเว้นตัวชี้โมฆะถ้าอาร์เรย์มีการอ้างอิงเป็นโมฆะก่อนค่าเป้าหมาย
ซามูเอลเอ็ดวินวอร์ด

1
คำสั่ง if ควรเป็น: if (targetValue.equals (s)) เพราะ String เท่ากับมีตัวตรวจสอบอินสแตนซ์ของ
TheArchon

ใช้ Objects.equals (obj1, obj2) แทนเพื่อความปลอดภัย
ตอนจบ


5
  1. สำหรับอาร์เรย์ที่มีความยาว จำกัด ให้ใช้ดังต่อไปนี้ (ตามที่กำหนดโดยcamickr ) สิ่งนี้ช้าสำหรับการตรวจสอบซ้ำโดยเฉพาะอย่างยิ่งสำหรับอาร์เรย์ที่ยาวกว่า (การค้นหาเชิงเส้น)

     Arrays.asList(...).contains(...)
  2. เพื่อประสิทธิภาพที่รวดเร็วหากคุณตรวจสอบองค์ประกอบที่ใหญ่กว่าซ้ำหลายครั้ง

    • อาร์เรย์เป็นโครงสร้างที่ไม่ถูกต้อง ใช้ 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);

4
รำคาญกับทำไมTreeSet? HashSetเร็วกว่า (O (1)) และไม่ต้องการสั่งซื้อ
Sean Owen

4

ลองสิ่งนี้:

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");
}

4

ใช้วิธีการต่อไปนี้ ( 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()ที่ใช้ในสถานที่อื่นเช่นกัน


ฉันมาช้ามากที่จะเข้าร่วมการสนทนานี้ แต่เนื่องจากวิธีการของฉันในการแก้ปัญหานี้เมื่อฉันเผชิญกับมันเมื่อไม่กี่ปีที่ผ่านมามีความแตกต่างเล็กน้อยจากคำตอบอื่น ๆ ที่โพสต์ไว้ที่นี่แล้ว ตรงนี้ในกรณีที่ใคร ๆ เห็นว่ามีประโยชน์
Abhishek Oza

3

ตรวจสอบสิ่งนี้

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
    }
}

1
นี้ไม่ได้ทำงาน - มันจะใส่elseสำหรับทุกรายการที่ไม่ตรงกับ (ดังนั้นหากคุณกำลังมองหา "AB" ในอาร์เรย์นั้นก็จะไปที่นั่น 3 ครั้งตั้งแต่วันที่ 3 ของค่าไม่ได้ "AB ")
Bernhard Barker

3

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) มันเป็นเพียงเสื้อคลุมที่มีน้ำหนักเบา ลองดูที่การนำไปปฏิบัติ
Patrick Parker


2

ใช้Array.BinarySearch(array,obj)สำหรับค้นหาวัตถุที่กำหนดในอาร์เรย์หรือไม่

ตัวอย่าง:

if (Array.BinarySearch(str, i) > -1)`  true --exists

false - ไม่มีอยู่


4
Array.BinarySearchและArray.FindIndexเป็นวิธีการ. NET และไม่มีอยู่ใน Java
ataylor

@ataylor มี Arrays.binarySearch เป็นภาษาจาวา แต่คุณถูกต้องไม่มี Arrays.findIndex
mente

ควรสังเกต:The array must be sorted prior to making this call. If it is not sorted, the results are undefined.
Dorian Gray

1

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


1

ลองใช้วิธีการทดสอบเพรดิเคตของ 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


0

การใช้ 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 );


-2

คุณสามารถตรวจสอบได้สองวิธี

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));  

    }

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