objects ¿Cómo determinar si una matriz contiene un valor particular en Java?




string array java (20)

Tengo una String[] con valores así:

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

Dado String s , ¿hay una buena manera de probar si VALUES contiene s ?


Puede utilizar la clase Arrays para realizar una búsqueda binaria del valor. Si su matriz no está ordenada, tendrá que usar las funciones de clasificación en la misma clase para ordenar la matriz, y luego buscarla.


En realidad, si usa HashSet como Tom Hawtin propuso, no necesita preocuparse por la clasificación y su velocidad es la misma que con la búsqueda binaria en una matriz preclasificada, probablemente incluso más rápida.

Todo depende de cómo esté configurado su código, obviamente, pero desde mi punto de vista, el orden sería:

En una matriz sin clasificar:

  1. HashSet
  2. comoLista
  3. ordenar y binario

En una matriz ordenada:

  1. HashSet
  2. Binario
  3. comoLista

Así que de cualquier manera, HashSet ftw


Por lo que vale la pena hice una prueba comparando las 3 sugerencias de velocidad. Generé enteros aleatorios, los convertí en una cadena y los agregué a una matriz. Luego busqué el número / cadena más alto posible, que sería el peor de los casos para asList (). Contiene ().

Cuando se usa un tamaño de matriz de 10 K, los resultados son:

Sort & Search   : 15
Binary Search   : 0
asList.contains : 0

Cuando se usa una matriz de 100 K, los resultados son:

Sort & Search   : 156
Binary Search   : 0
asList.contains : 32

Por lo tanto, si la matriz se crea en orden, la búsqueda binaria es la más rápida, de lo contrario, asList () será el camino a seguir. Si tiene muchas búsquedas, puede valer la pena ordenar la matriz para que pueda usar la búsqueda binaria. Todo depende de su aplicación.

Pensaría que esos son los resultados que la mayoría de la gente esperaría. Aquí está el código de prueba:

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

Sólo para borrar el código para empezar. Tenemos (corregido):

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

Esta es una estática mutable que FindBugs te dirá que es muy mala. Debería ser privado:

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

(Tenga en cuenta que realmente puede soltar la new String[]; bit.)

Entonces, las matrices de referencia son malas, y en particular aquí queremos un conjunto:

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

(Las personas paranoicas, como yo, pueden sentirse más cómodas si esto se envolvió en Collections.unmodifiableSet . Collections.unmodifiableSet no modificable, incluso podría hacerse público).

"Dado String s, ¿hay una buena manera de probar si VALUES contiene s?"

VALUES.contains(s)

O (1).


Crear un booleano inicialmente establecido en falso. Ejecute un bucle para verificar cada valor en la matriz y comparar con el valor con el que está comparando. Si alguna vez obtiene una coincidencia, establezca boolean en verdadero y detenga el bucle. Luego afirma que el booleano es verdadero.



Arrays.asList () ->, entonces, llamar al método contiene () siempre funcionará, pero un algoritmo de búsqueda es mucho mejor, ya que no es necesario crear una envoltura de lista ligera alrededor de la matriz, que es lo que hace 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.
}

Si tiene la biblioteca de colecciones de Google, la respuesta de Tom se puede simplificar mucho usando ImmutableSet (http://google-collections.googlecode.com/svn/trunk/javadoc/com/google/common/collect/ImmutableSet.html)

Esto realmente elimina una gran cantidad de desorden de la inicialización propuesta

private static final Set<String> VALUES =  ImmutableSet.of("AB","BC","CD","AE");

  1. Para matrices de longitud limitada, use lo siguiente (como se indica en camickr ). Esto es lento para verificaciones repetidas, especialmente para arreglos más largos (búsqueda lineal).

     Arrays.asList(...).contains(...)
    
  2. Para un rendimiento rápido si se verifica repetidamente contra un conjunto más grande de elementos

    • Una matriz es la estructura incorrecta. Use un TreeSet y agregue cada elemento a él. Ordena los elementos y tiene un método rápido de exist() (búsqueda binaria).

    • Si los elementos implementan Comparable y desea que el TreeSet consecuencia:

      ElementClass.compareTo() método ElementClass.compareTo() debe ser compatible con ElementClass.equals() : ¿ver Triadas que no aparecen para luchar? (Java Set falta un elemento)

      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));
      
    • De lo contrario, usa tu propio 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);
      
    • La recompensa: comprobar la existencia de algún elemento:

      // Fast binary search through sorted elements (performance ~ log(size)):
      boolean containsElement = myElements.exists(someElement);
      

Arrays.asList(yourArray).contains(yourValue)

Advertencia: esto no funciona para matrices de primitivos (ver los comentarios).

Desde java-8 ahora puedes usar Streams.

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

Para verificar si una matriz de int , double o long contiene un valor, use IntStream , DoubleStream o LongStream respectivamente.

Ejemplo

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

ObStupidAnswer (pero creo que hay una lección aquí en alguna parte):

enum Values {
    AB, BC, CD, AE
}

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

Llego muy tarde para unirme a esta discusión, pero desde que abordé este problema, cuando lo enfrenté hace unos años, era un poco diferente a las otras respuestas ya publicadas aquí, estoy publicando la solución que usé en ese momento, aquí, en caso de que alguien lo encuentre útil: (el método contains() es ArrayUtils.in() en este código).

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

}

Como puede ver en el código anterior, hay otros métodos de utilidad ObjectUtils.equals() y ArrayUtils.indexOf() , que también se usaron en otros lugares.


Use Array.BinarySearch(array,obj) para encontrar el objeto dado en array o no. Ex:

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

falso - no existe


Si no quieres que sea sensible a las mayúsculas

Arrays.stream(VALUES).anyMatch(s::equalsIgnoreCase);

Si la matriz no está ordenada, tendrá que iterar sobre todo y hacer una llamada a iguales en cada uno.

Si la matriz está ordenada, puede hacer una búsqueda binaria, hay una en la clase Arrays .

En general, si va a realizar muchas comprobaciones de membresía, es posible que desee almacenar todo en un Conjunto, no en una matriz.


En lugar de usar la sintaxis de inicialización de matriz rápida para usted, solo puede iniciarlo como una lista de forma similar utilizando el método Arrays.asList, por ejemplo:

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

Luego puedes hacer (como arriba): STRINGS.contains("the string you want to find");


Una posible solución:

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

Prueba esto:

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

Me sorprende que nadie sugiriera simplemente implementarlo a mano:

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

Mejora:

La condición v != null es constante dentro del método, siempre se evalúa al mismo valor booleano durante la llamada al método. Entonces, si la array entrada es grande, es más eficiente evaluar esta condición solo una vez y podemos usar una condición simplificada / más rápida dentro del bucle for basado en el resultado. El método mejorado 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;
}

Usar un bucle simple es la forma más eficiente de hacer esto.

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

Cortesía de Programcreek





arrays