Soru Bir dizinin belirli bir değer içerip içermediğini nasıl test edebilirim?


Benim bir String[] böyle değerleri ile:

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

verilmiş String s, test etmenin iyi bir yolu var mı VALUES içeren s?


1855
2017-07-15 00:03


Menşei


Etrafında uzun yol var, ancak for döngüsünü kullanabilirsiniz: "for (String s: VALUES) (s.equals (" MYVALUE ")) true olursa; - Zack
Neden insanlar hala bu cevabı geri çeviriyorlar (şimdi 75)? Onun 2 yaşında ve çok basit bir cevap. Tek yaptığım birisini bir API metoduna işaret ediyordu. Herhangi bir cevabın bu kadar değerli olan bu hainliği hak ettiğini düşünmüyorum. - camickr
@camickr. Sorunuza, bu soruyu ve cevabınızı yedim, çünkü -böyle- 30 dakika ve 20 satırlık kodları çirkin yazmak için kurtardı, -now-. Üç yıl önce okumadım. (BTW, teşekkürler :)) - Pursuit
@ camickr - Ben bununla neredeyse aynı durum var: stackoverflow.com/a/223929/12943  Sadece oy almaya devam ediyor, ancak güneş belgelerinden sadece bir kopya / yapıştır. Skor, ne kadar yardım ettiğinizi değil, ne kadar çaba harcadığınızı ve ne kadar hızlı bir şekilde yayınladığınızı temel alıyor. Belki de John Skeet'in sırrına tökezledik! İyi bir cevap, senin için +1. - Bill K
@camickr çünkü insanlar, benim gibi, google bir soru, SO sonucunu tıklayın, cevabınızı görün, test edin, işe yarıyor, cevabı tekrar verin ve bırakın. - Aequitas


Cevaplar:


Arrays.asList(yourArray).contains(yourValue)

Uyarı: Bu, ilkellerin dizileri için işe yaramaz (bkz. Yorumlar).


Dan beri

Artık bir Stream bir dizi olup olmadığını kontrol etmek int, double veya long bir değer içerir (sırasıyla IntStream, DoubleStream veya LongStream)

Örnek

int[] a = {1,2,3,4};
boolean contains = IntStream.of(a).anyMatch(x -> x == 4);

2428
2017-07-15 00:04



Bir dizi üzerinde yineleme ve bir equals () işlevi veya ilkeller için == kullanarak, Arrays sınıfındaki arama işlevlerine karşı bu performansın performansı hakkında biraz merak ediyorum. - Thomas Owens
List (), kalbinde bir dizi olan bir ArrayList döndürdüğü için, çok fazla kaybetmezsiniz. Kurucu sadece bir referansı değiştirecektir, bu yüzden orada yapılması gereken çok iş yoktur. Ve içerir () / indexOf () yineleme ve eşittir () kullanır. İlkel insanlar için, kodlamadan daha iyi olmalısın. Dizeler veya diğer sınıflar için fark göze çarpmayacaktır. - Joey
Garip, NetBeans, 'int [] tatilleri için' Arrays.asList (tatil günleri) 'nin bir' liste <int []> 'döndürdüğünü ve bir' liste <int> 'döndürmediğini iddia eder. Sadece tek bir eleman içerir. İçindekiler, tek bir elemente sahip olduğu için işe yaramıyor; int dizisi. - Nyerguds
Nyerde'lar: Aslında, bu ilkel için işe yaramaz. Java'da ilkel türler jenerik olamaz. asList <T> List <T> asList (T ...) olarak bildirilmiştir. Bir int [] 'in içine girdiğinizde, derleyici T = int []' ı aştı çünkü T = int sonucunu çıkaramaz çünkü ilkeller jenerik olamaz. - CromTheDestroyer
@Joey sadece bir yan not, bu bir ArrayList, Ama değil java.util.ArrayList beklediğiniz gibi, geri dönen gerçek sınıf: java.util.Arrays.ArrayList<E> olarak tanımlandı: public class java.util.Arrays {private static class ArrayList<E> ... {}}. - TWiStErRob


Sadece başlamak için kodu temizlemek için. Elimizde (düzeltildi):

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

Bu FindBugs'ın size çok yaramaz olduğunu söyleyeceği değişebilir bir statiktir. Özel olmalı:

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

(Not, aslında bırakabilirsiniz new String[]; bit.)

Yani, referans dizileri kötüydü ve özellikle burada bir set istiyoruz:

private static final Set<String> VALUES = new HashSet<String>(Arrays.asList(
     new String[] {"AB","BC","CD","AE"}
));

(Paranoyak insanlar, kendim gibi, eğer sarılmışsa daha rahat hissedebilir) Collections.unmodifiableSet - halka açık bile yapılabilirdi.

"Verilen String s, VALUES'in s içerip içermediğini test etmenin iyi bir yolu var mı?"

VALUES.contains(s)

O (1).


309
2017-07-15 01:13



İlk başta koleksiyon oluşturmak için O (N) hariç :) - Drew Noakes
Statik ise, muhtemelen birkaç kez kullanılacaktır. Bu nedenle, kümeyi başlatmak için harcanan zaman, çok sayıda doğrusal aramanın maliyetine kıyasla oldukça küçük olma şansına sahiptir. - Xr.
Daha sonra koleksiyonun kod yükleme süresi (teknik olarak O (n) fakat pratik olarak sabit olan) tarafından baskın hale gelecektir. - Tom Hawtin - tackline
@ TomHawtin-tackline Neden "burada bir set istiyoruz" diyorsunuz? Bu durumda bir Set'in (HashSet) avantajı nedir? Neden bir "referans dizisi" kötüyse ("referans dizisi" ile bir çağrı tarafından oluşturulan bir dizi tarafından desteklenen bir ArrayList kastedilmektedir Arrays.asList)? - Basil Bourque
@nmr A TreeSet olabilir O(log n). HashSetBir kovadaki ortalama eleman sayısı kabaca sabit olacak şekilde ölçeklenir. En az 2 ^ 30'a kadar olan diziler için. Büyük O analizinin göz ardı ettiği donanım önbelleklerinden etkilenebilir. Ayrıca karma işlevinin etkin bir şekilde çalıştığını varsayar. - Tom Hawtin - tackline


Kullanabilirsiniz ArrayUtils.contains itibaren Apache Commons Lang

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

Bu yöntemin geri döndüğünü unutmayın false geçirilen dizi ise null.

Her türlü ilkel diziler için de yöntemler mevcut.

Örnek:

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

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

171
2018-05-31 13:17



78kb android uygulama için 300kb kütüphane, her zaman iyi değil - max4ever
@ max4ever Katılıyorum, ama bu hala "kendi yuvarlanmasını" daha iyi ve daha sonra ham java yolunu okumak daha kolay. - Jason
paketi: org.apache.commons.lang.ArrayUtils - slamborne
@ max4ever Bazen bu kütüphaneyi (başka sebeplerden dolayı) zaten almışsınızdır ve tam olarak geçerli bir cevaptır. Bunu arıyordum ve zaten Apache Commons Lang'e bağlıyım. Bu cevap için teşekkürler. - GuiSim
@ max4ever Çoğu android uygulaması Proguard tarafından minimalleştirilir, sadece uygulamanıza ihtiyacınız olan sınıfları ve fonksiyonları getirir. Bu kendi kendine yuvarlanmayı veya apache olayının kaynağını kopyalamayı eşit hale getirir. Ve kim bu minimalizasyon kullanmazsa, 700kb veya 78kb hakkında şikayette bulunmanız gerekmez :) - Kenyakorn Ketsombut


Şaşkınım, hiç kimse sadece elle uygulamamayı önermedi:

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

Gelişme iyilesme duzelme ilerleme:

v != null Durum, yöntem içinde sabittir, yöntem çağrısı sırasında her zaman aynı boole değerine döner. Yani giriş array büyüktür, bu koşulu sadece bir kez değerlendirmek daha verimlidir ve basitleştirilmiş / daha hızlı bir koşulu kullanabiliriz. for sonuca göre döngü. Geliştirilmiş contains() yöntem:

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

142
2017-09-28 07:45



@Phoexo Bu çözüm açıkça daha hızlıdır çünkü kabul edilen cevap diziyi bir listeye sarar ve çözümün temelde ne yaptığını () yalnızca yapacağı şeyi yaparken bu listede includes () yöntemini çağırır. - icza
@AlastorMoody e == v çok hızlı bir referans eşitlik kontrolü yapar. Aynı nesne (referans ile aynı) dizide ise, daha hızlı bulunur. Aynı örnek değilse, hala eşittir () yöntemi tarafından talep edilenle aynı olabilir, referanslar aynı değilse, bu kontrol edilir. - icza
Bu işlev neden Java'nın bir parçası değil? Hiç şüphe yok ki insanlar Java'nın şişirildiğini söylerler… yukarıdaki tüm cevaplara bakmanız yeterlidir. Çocuklar bugünlerde! - phreakhead
@phreakhead Java'nın bir parçasıdır, bkz. Collection.contains(Object) - Steve Kuo
@icza Kaynağına bakarsanız Arrays ve ArrayList Bu, mutlaka, kullanılan sürümden daha hızlı değil. Arrays.asList(...).contains(...). Yaratmanın ek yükü ArrayList son derece küçük ve ArrayList.contains() daha akıllı bir döngü kullanır (aslında iki farklı döngü kullanır), yukarıda gösterilenlerden daha fazladır (JDK 7). - Axel


Dizi sıralanmazsa, her şey üzerinde yinelemek ve her birine eşit olmak için bir çağrı yapmak zorunda kalacaksınız.

Dizi sıralanırsa, bir ikili arama yapabilirsiniz. Diziler sınıf.

Genel olarak, çok fazla üyelik kontrolü yapacaksanız, her şeyi bir dizide değil, bir Küme içinde saklamak isteyebilirsiniz.


65
2017-07-15 00:05



Ayrıca, cevabımda söylediğim gibi, Arrays sınıfını kullanırsanız, diziyi sıralayabilir ve yeni sıralanmış dizide ikili aramayı gerçekleştirebilirsiniz. - Thomas Owens
@Thomas: Katılıyorum. Ya da her şeyi bir TreeSet'e ekleyebilirsiniz; aynı karmaşıklık. Eğer diziler değişmezse diziler kullanırdım (belki de diziler olmasa bile, referanslar bitişik olarak yerleştirildiklerinden birazcık hafıza yeri saklayabilirler). Eğer bu zamanla değişecekse seti kullanırdım. - Uri


Bir Dizinin Bir Değer İçermiş Olduğunu Kontrol Etmenin Dört Farklı Yolu

1) kullanma listesi:

public static boolean useList(String[] arr, String targetValue) {
    return Arrays.asList(arr).contains(targetValue);
}

2) Setin Kullanımı:

public static boolean useSet(String[] arr, String targetValue) {
    Set<String> set = new HashSet<String>(Arrays.asList(arr));
    return set.contains(targetValue);
}

3) Basit bir döngü kullanarak:

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

4) Arrays.binarySearch () kullanarak:

Aşağıdaki kod yanlıştır, burada tamlık için listelenmiştir. binarySearch () SADECE sıralı dizilerde kullanılabilir. Sonuçları aşağıda tuhaf bulacaksınız. Dizi sıralandığında bu en iyi seçenektir.

public static boolean binarySearch(String[] arr, String targetValue) {  
            int a = Arrays.binarySearch(arr, targetValue);
            return a > 0;
        }

Hızlı örnek:

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

59
2018-05-07 19:14



ikili arama örneğiniz bir> 0 döndürmelidir; - Will Sherwood
Niye ya? Sanırım bir> -1 döndürmeli, çünkü 0 dizinin başında yer aldığını gösterir. - mbelow
İle ilk varyant (a >= 0) doğruydu, sadece kontrol et dokümanlar, "Bunun, eğer anahtar bulunursa, dönüş değerinin> = 0 olacağını garanti ettiklerini" belirtiyorlar. - Yoory N.


Onun değeri için 3 hız önerisini karşılaştıran bir test yaptım. Rastgele tam sayıları oluşturdum, bir String'e dönüştürdüm ve bunları bir diziye ekledim. Daha sonra mümkün olan en yüksek sayı / dizgiyi aradım ve bu da asList (). İncludes () için en kötü durum senaryosu olurdu.

10K dizi boyutunu kullanırken sonuçları nerede:

Sırala & Ara: 15
İkili Arama: 0
asList.contains: 0

Bir 100K dizi kullanırken sonuçları nerede:

Sırala & Ara: 156
İkili Arama: 0
asList.contains: 32

Yani sıralı sırayla oluşturulursa, ikili arama en hızlı, aksi takdirde asList () içerir. Çok sayıda aramanız varsa, diziyi sıralamak faydalı olabilir, böylece ikili aramayı kullanabilirsiniz. Hepsi uygulamanıza bağlı.

Bunların çoğu insanın beklediği sonuçlar olduğunu düşünürdüm. İşte test kodu:

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

46
2017-07-15 01:28



Bu kodu anlamıyorum. 'Dizeleri' dizisini sıralar ve her iki aramada da aynı (sıralanmış) diziyi binarySearch'te kullanırsınız. Bu, HotSpot çalışma zamanı optimizasyonu dışında nasıl bir şey gösterebilir? AsList.contains çağrısı ile aynı. Sıralı diziden bir liste oluşturursunuz ve daha sonra en yüksek değeri içeren bir liste oluşturur. Tabii ki zaman alacak. Bu testin anlamı nedir? Yanlış yazılmış bir mikrobenzenlikten bahsetmemek - Erik
Ayrıca, ikili arama yalnızca sıralı bir kümeye uygulanabildiğinden, ikili aramayı kullanmanın tek yolu sıralama ve aramadır. - Erik
Sıralama, bir dizi başka sebepten dolayı önceden yapılmış olabilir, örneğin, init olarak sıralanabilir ve hiçbir zaman değiştirilemez. Arama süresinin kendi başına test edilmesinde kullanılır. Bununla birlikte, bu durumun düştüğü yerde, mikro beneklemenin yıldız örneğinden daha az olduğu görülmektedir. Microbenchmarks'ın Java'da doğru bir şekilde elde edilmesi oldukça zordur ve örneğin gerçek testi çalıştırmadan önce gerçek test kodunu bir zamanlayıcı ile ONCE'den daha fazla çalıştırmaya izin vermeden önce, test kodunun gerçek testin yapılmasından önce hotspot optimizasyonu elde etmeye yetecek kadar çalıştırılması gerekir. Örnek tuzaklar - Thor84no
Bu test, 3 testin tümünü çalıştırdığı için kusurludur. aynı JVM örneği. Daha sonraki testler önbellek, JIT, vb ısınma öncekilerden yararlanabilir - Steve Kuo
Bu test aslında tamamen ilgisiz. Sıralama & Arama, doğrusal (n * log (n)) karmaşıklığı, ikili arama logaritmik ve ArrayUtils.contains'ın doğrusal olduğu doğrusaldır. Bu çözümleri tamamen farklı karmaşıklık sınıflarında olduğu gibi karşılaştırmak hiç bir işe yaramıyor. - dragn


Hızlı dizi ilkleme sözdizimini kullanmak yerine, bunu Arrays.asList yöntemini kullanarak benzer bir şekilde hemen bir Liste olarak hemen başlatabilirsiniz.

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

Sonra yapabilirsin (yukarıdaki gibi): STRINGS.contains("the string you want to find");


29
2018-01-20 13:58





Java 8 ile bir akış oluşturabilir ve akıştaki herhangi bir girişin eşleşip eşleşmediğini kontrol edebilirsiniz. "s":

String[] values = {"AB","BC","CD","AE"};
boolean sInArray = Arrays.stream(values).anyMatch("s"::equals);

Veya genel bir yöntem olarak:

public static <T> boolean arrayContains(T[] array, T value) {
    return Arrays.stream(array).anyMatch(value::equals);
}

29
2018-03-13 14:53



İlkel uzmanlıkları da not etmeye değer. - skiwi
Ayrıca eklemek için anyMatch JavaDoc bunu belirtir "...May not evaluate the predicate on all elements if not necessary for determining the result."Bu nedenle, bir eşleşme bulduktan sonra işleme devam etmeye gerek olmayabilir. - mkobit


Kullanabilirsiniz Diziler sınıfı Değer için ikili arama yapmak. Diziniz sıralanmazsa, diziyi sıralamak için sıralamada aynı sınıftaki sıralama işlevlerini kullanmanız ve ardından arama yapmanız gerekir.


22
2017-07-15 00:05



Bunu başarmak için sıralama işlevlerini aynı sınıfta kullanabilirsiniz ... Bunu yanıtıma eklemeliyim. - Thomas Owens
Muhtemelen asList (). İncludes () yaklaşımından daha pahalıya mal olacak, o zaman bence. Bu kontrolü çok sık yapmanız gerekmedikçe (ancak, başlangıçta sıralanabilecek, adil olabilen değerlerin statik bir listesi ise). - Joey
Doğru. En etkili olacak çok değişken var. Yine de seçeneklere sahip olmak güzel. - Thomas Owens
Bize bunun nasıl yapılacağını gösterir misiniz? - AHH
Bunu yapan bazı kodlar: stackoverflow.com/a/48242328/9131078 - O.O.Balance