Tengo un String[]
con valores como este:
public static final String[] VALUES = new String[] {"AB","BC","CD","AE"};
Dado String s
, ¿hay una buena manera de probar si VALUES
contiene s
?
Tengo un String[]
con valores como este:
public static final String[] VALUES = new String[] {"AB","BC","CD","AE"};
Dado String s
, ¿hay una buena manera de probar si VALUES
contiene s
?
Respuestas:
Arrays.asList(yourArray).contains(yourValue)
Advertencia: esto no funciona para matrices de primitivas (ver los comentarios).
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 IntStream
, use , DoubleStream
o LongStream
respectivamente.
int[] a = {1,2,3,4};
boolean contains = IntStream.of(a).anyMatch(x -> x == 4);
ArrayList
, pero no java.util.ArrayList
como se esperaba, la clase real, se volvió: java.util.Arrays.ArrayList<E>
definida como: public class java.util.Arrays {private static class ArrayList<E> ... {}}
.
Las matrices de referencia son malas. Para este caso estamos tras un conjunto. Desde Java SE 9 tenemos Set.of
.
private static final Set<String> VALUES = Set.of(
"AB","BC","CD","AE"
);
"Dado String s, ¿hay una buena manera de probar si VALUES contiene s?"
VALUES.contains(s)
O (1).
El tipo correcto , inmutable , O (1) y conciso . Hermoso.*
Solo 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 le dirá que es muy traviesa. No modifique las estadísticas y no permita que otros códigos también lo hagan. Como mínimo absoluto, el campo debe ser privado:
private static final String[] VALUES = new String[] {"AB","BC","CD","AE"};
(Nota, en realidad puedes soltar el new String[];
bit).
Las matrices de referencia siguen siendo malas y 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 a gusto si esto se envuelve Collections.unmodifiableSet
, incluso podría hacerse público).
(* Para ser un poco más sobre la marca, es previsible que la API de colecciones todavía no tenga tipos de colección inmutables y la sintaxis sigue siendo demasiado detallada, para mis gustos).
Arrays.asList
)?
TreeSet
lo sería O(log n)
. HashSet
s se escalan de tal manera que el número medio de elementos en un cubo es aproximadamente constante. Al menos para matrices de hasta 2 ^ 30. Puede haber efectos de, por ejemplo, cachés de hardware que el análisis big-O ignora. También supone que la función hash está funcionando de manera efectiva.
Puedes usar ArrayUtils.contains
desde Apache Commons Lang
public static boolean contains(Object[] array, Object objectToFind)
Tenga en cuenta que este método se devuelve false
si la matriz aprobada es null
.
También hay métodos disponibles para matrices primitivas de todo tipo.
String[] fieldsToInclude = { "id", "name", "location" };
if ( ArrayUtils.contains( fieldsToInclude, "id" ) ) {
// Do some stuff.
}
Simplemente impleméntelo 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 v != null
condición es constante dentro del método. Siempre se evalúa con el mismo valor booleano durante la llamada al método. Entonces, si la entrada array
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 for
ciclo en función del resultado. El contains()
método mejorado :
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
y ArrayList
resulta que esto no es necesariamente más rápido que la versión que usa Arrays.asList(...).contains(...)
. La sobrecarga de crear una ArrayList
es extremadamente pequeña y ArrayList.contains()
utiliza un bucle más inteligente (en realidad usa dos bucles diferentes) que el que se muestra arriba (JDK 7).
Cuatro formas diferentes de verificar si una matriz contiene un valor
1) Uso de la lista:
public static boolean useList(String[] arr, String targetValue) {
return Arrays.asList(arr).contains(targetValue);
}
2) Usando Set:
public static boolean useSet(String[] arr, String targetValue) {
Set<String> set = new HashSet<String>(Arrays.asList(arr));
return set.contains(targetValue);
}
3) Usando un bucle simple:
public static boolean useLoop(String[] arr, String targetValue) {
for (String s: arr) {
if (s.equals(targetValue))
return true;
}
return false;
}
4) Usando Arrays.binarySearch ():
El siguiente código es incorrecto, se enumera aquí para completar. binarySearch () SOLO se puede usar en matrices ordenadas. Encontrará que el resultado es extraño a continuación. Esta es la mejor opción cuando se ordena la matriz.
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
(a >= 0)
era correcta, solo verifique los documentos , dicen "Tenga en cuenta que esto garantiza que el valor de retorno será> = 0 si y solo si se encuentra la clave".
Si la matriz no está ordenada, deberá 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 términos generales, si va a hacer muchas comprobaciones de membresía, es posible que desee almacenar todo en un Conjunto, no en una matriz.
Por lo que vale, realicé 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 el asList().contains()
.
Al usar un tamaño de matriz de 10K, los resultados fueron:
Ordenar y buscar: 15 Búsqueda binaria: 0 asList.contains: 0
Cuando se usa una matriz de 100K, los resultados fueron:
Ordenar y buscar: 156 Búsqueda binaria: 0 asList.contains: 32
Entonces, si la matriz se crea en orden ordenado, la búsqueda binaria es la más rápida, de lo contrario, este asList().contains
sería 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 tu aplicación.
Creo 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));
}
}
En lugar de utilizar también la sintaxis de inicialización de matriz rápida, puede inicializarla como una Lista directamente de manera similar utilizando el método Arrays.asList, por ejemplo:
public static final List<String> STRINGS = Arrays.asList("firstString", "secondString" ...., "lastString");
Entonces puedes hacer (como arriba):
STRINGS.contains("the string you want to find");
Con Java 8 puede crear una secuencia y verificar si alguna entrada en la secuencia coincide "s"
:
String[] values = {"AB","BC","CD","AE"};
boolean sInArray = Arrays.stream(values).anyMatch("s"::equals);
O como un método genérico:
public static <T> boolean arrayContains(T[] array, T value) {
return Arrays.stream(array).anyMatch(value::equals);
}
anyMatch
JavaDoc lo indica "...May not evaluate the predicate on all elements if not necessary for determining the result."
, por lo que es posible que no necesite continuar el procesamiento después de encontrar una coincidencia.
Puede usar 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.
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;
}
En realidad, si usa HashSet <String> como lo propuso Tom Hawtin, no necesita preocuparse por la clasificación, y su velocidad es la misma que con la búsqueda binaria en una matriz preseleccionada, probablemente incluso más rápido.
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 :
En una matriz ordenada:
De cualquier manera, HashSet para la victoria.
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 mucho desorden de la inicialización propuesta
private static final Set<String> VALUES = ImmutableSet.of("AB","BC","CD","AE");
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");
}
}
}
Los desarrolladores a menudo hacen:
Set<String> set = new HashSet<String>(Arrays.asList(arr));
return set.contains(targetValue);
El código anterior funciona, pero no es necesario convertir una lista para establecer primero. La conversión de una lista a un conjunto requiere tiempo adicional. Puede ser tan simple como:
Arrays.asList(arr).contains(targetValue);
o
for(String s: arr){
if(s.equals(targetValue))
return true;
}
return false;
El primero es más legible que el segundo.
Usar un bucle simple es la forma más eficiente de hacerlo.
boolean useLoop(String[] arr, String targetValue) {
for(String s: arr){
if(s.equals(targetValue))
return true;
}
return false;
}
Cortesía de Programcreek.
En Java 8 use 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);
Para matrices de longitud limitada, use lo siguiente (como lo proporciona camickr ). Esto es lento para verificaciones repetidas, especialmente para matrices más largas (búsqueda lineal).
Arrays.asList(...).contains(...)
Para un rendimiento rápido si verifica repetidamente contra un conjunto de elementos más grande
Una matriz es la estructura incorrecta. Use ay TreeSet
agregue cada elemento. Ordena elementos y tiene un exist()
método rápido (búsqueda binaria).
Si los elementos se implementan Comparable
y desea TreeSet
ordenarlos en consecuencia:
ElementClass.compareTo()
El método debe ser compatible con ElementClass.equals()
: ¿Ver Tríadas 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, use el suyo 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: verificar la existencia de algún elemento:
// Fast binary search through sorted elements (performance ~ log(size)):
boolean containsElement = myElements.exists(someElement);
TreeSet
? HashSet
es más rápido (O (1)) y no requiere orden.
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");
}
Use lo siguiente (el contains()
método está 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.
Mira esto
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
para cada elemento que no coincida (por lo que si está buscando "AB" en esa matriz, irá allí 3 veces, ya que 3 de los valores no son "AB" ").
Arrays.asList () -> luego llamar al método contiene () siempre funcionará, pero un algoritmo de búsqueda es mucho mejor ya que no necesita crear un envoltorio de lista ligero 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.
}
Arrays.asList
no es O (n). Es solo una envoltura ligera. Echa un vistazo a la implementación.
Si no quieres que sea sensible a mayúsculas y minúsculas
Arrays.stream(VALUES).anyMatch(s::equalsIgnoreCase);
Se usa Array.BinarySearch(array,obj)
para encontrar el objeto dado en una matriz o no.
Ejemplo:
if (Array.BinarySearch(str, i) > -1)` → true --exists
falso: no existe
Array.BinarySearch
y Array.FindIndex
son métodos .NET y no existen en Java.
The array must be sorted prior to making this call. If it is not sorted, the results are undefined.
Cree un booleano inicialmente establecido en falso. Ejecute un bucle para verificar cada valor en la matriz y compárelo con el valor con el que está comprobando. Si alguna vez obtiene una coincidencia, establezca boolean en true y detenga el bucle. Luego afirme que el booleano es verdadero.
Intente usar el método de prueba de predicado Java 8
Aquí hay un ejemplo completo de ello.
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
el uso de a Spliterator
previene la generación innecesaria de 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
si search
está contenido en la matriz
esto hace el trabajo para las matrices de primitivas
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 );
…
Como estoy tratando con Java de bajo nivel usando tipos primitivos byte y byte [], lo mejor que he obtenido hasta ahora es de bytes-java https://github.com/patrickfav/bytes-java parece un buen trabajo
Puedes verificarlo por dos métodos
A) Al convertir la matriz en cadena y luego verificar la cadena requerida por el método .contains
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) este es un método más eficiente
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));
}