Проверьте, содержит ли ArrayList массив

#java #arrays #arraylist #contains

#java #массивы #arraylist #содержит

Вопрос:

У меня есть ArrayList, который содержит массивы. Как мне проверить, содержит ли ArrayList указанный массив? Я использовал .contains метод, и он возвращает false вместо ожидаемого true .

 import java.util.ArrayList;
import java.util.Arrays;

public class main {
    public static void main(String[] args) {
        ArrayList<String[]> action = new ArrayList<String[]>();
        action.add(new String[]{"appple", "ball"});
        String[] items = new String[]{"appple", "ball"};
        if (action.contains(new String[]{"appple", "ball"})) {
            System.out.println("Yes");
        }
        System.out.println(action.contains(items)); // False
    }
}
 

Комментарии:

1. Это выглядит как плохой дизайн с самого начала. Рассмотрите возможность создания List<List<String>> или переноса массива в класс, который использует java.util.Arrays.equals и java.util.Arrays.hashCode как свои собственные методы equals и hashCode .

Ответ №1:

Метод ‘contains’ сравнивает эквивалентные значения хэш-кода.

Поэтому, если вы сделаете это, как показано ниже *, оно пройдет.

 public class main {
    public static void main(String[] args) {
        ArrayList<String[]> action = new ArrayList<String[]>();

        String[] items = new String[]{"appple","ball"};
        action.add(items);

        System.out.println("TO STRING");
        System.out.println("--" action.get(0));
        System.out.println("--" new String[]{"apple","ball"});

        System.out.println("HASHCODES");
        String[] sameValues = new String[]{"apple","ball"};
        System.out.println("--" action.get(0).hashCode());    
        System.out.println("--" items.hashCode());           
        System.out.println("--" sameValues.hashCode());    
       
        System.out.println("CONTAINS");
        System.out.println("--" action.contains(items));  // *this
        System.out.println("--" action.contains(sameValues));
        System.out.println("--" action.contains(new String[]{"apple","ball"}));
 
    }
}
 

результат:

 TO STRING
--[Ljava.lang.String;@7b1d7fff
--[Ljava.lang.String;@299a06ac
HASHCODES
--1243554231
--1243554231
--2548778887
CONTAINS
--true
--false
--false
 

Что касается кода, показанного при печати массива, они не переопределяются toString() , поэтому вы получаете:

getClass().getName() '@' Integer.toHexString(hashCode())

Например:

[Ljava.lang.String;@7b1d7fff

  • [ обозначает одномерный массив
  • Ljava.lang.String обозначает тип
  • @
  • 7b1d7fff Шестнадцатеричное представление хэш-кода

Однако, если вы хотите сравнить значения, существует следующий метод.

 public class main {
    public static void main(String[] args) {

        String[] items = new String[]{"apple","ball"};

        ArrayList<String> action = new ArrayList<>(Arrays.asList(items));

        if (action.contains("apple")) {
            System.out.println("Yes");
        }
    }
}
 

Ответ №2:

Вы можете выполнить итерацию по этому списку и для каждого элемента, т.Е. Массива, Вызвать Arrays.equals метод для проверки равенства массивов до первого совпадения или до конца списка, если ни один из них не совпадает. В этом случае он может возвращать true для каждого элемента:

 List<String[]> list = List.of(
        new String[]{"appple", "ball"},
        new String[]{"appple", "ball"});

String[] act = new String[]{"appple", "ball"};

System.out.println(list.stream()
        .anyMatch(arr -> Arrays.equals(arr, act))); // true
 

Этот метод внутренне вызывает String#equals метод для каждого элемента массива, т. Е. String , Поэтому этот код также возвращает true :

 List<String[]> list = List.of(
        new String[]{new String("appple"), new String("ball")},
        new String[]{new String("appple"), new String("ball")});

String[] act = new String[]{new String("appple"), new String("ball")};

System.out.println(list.stream()
        .anyMatch(arr -> Arrays.equals(arr, act))); // true
 

Ответ №3:

Поскольку вы создаете разные массивы (даже если содержимое одинаковое), contains приведет к false .

Однако, если вы сделаете это:

  List<String[]> action = new ArrayList<String[]>();
 String[] items = new String[]{"apple","ball"};   
 action.add(items);
 if (action.contains(items)) 
     System.out.println("Yes");
 

Это выведет Yes.
Кроме того, некоторые примеры поведения:

  String[] items = new String[]{"apple","ball"};   
 action.add(items);
 String[] clone = items.clone();
 String[] mirror = items;

 action.contains(clone); // false 
 action.contains(mirror); // true

 items[0]="horse";
 System.out.println(mirror[0]);        // "horse"
 System.out.println(clone[0]);         // "apple"
 System.out.println(action.get(0)[0]); // "horse"

 mirror[1]="crazy";
 System.out.println(clone[1]);         // "ball"
 System.out.println(action.get(0)[1]); // "crazy"
 System.out.println(items[1]);         // "crazy"

 clone[1]="yolo";
 System.out.println(action.get(0)[1]); // "crazy"
 System.out.println(items[1]);         // "crazy"
 System.out.println(mirror[1]);        // "crazy"

 System.out.println(action.get(0).hashCode());    //2018699554
 System.out.println(items.hashCode());            //2018699554
 System.out.println(clone.hashCode());            //1311053135
 System.out.println(mirror.hashCode());           //2018699554
 

Пользовательский « contains «

Проблема здесь в том, что если вы захотите впоследствии выполнить поиск по определенному массиву, вы потеряете ссылки, и поиск элемента будет невозможен, даже не реплицируя массив с теми же точными значениями.

В качестве обходного пути вы можете реализовать свой собственный contains метод. Что-то вроде:

Если вы хотите получить индекс:

 static int indexOfArray(List<String[]> list, String[] twin)
{        
   for (int i=0;i<list.size();i  )
      if (Arrays.equals(list.get(i),twin))
           return i;
   return -1;
}
 

А затем вызовите его следующим образом:

 String[] toSearch = new String[]{"apple","ball"};
int index = indexOfArray(action, toSearch); 

if (index>0) 
    System.out.println("Array found at index " index);
else
    System.out.println("Array not found");
 

Если индекс больше -1, вы можете получить свой исходный массив, просто:

 String[] myArray = action.get(index);
 

Хэш — карта идентификатор

Альтернативой может быть сохранение массивов в a HashMap путем объявления идентификатора для каждого массива. Например:

Идентификатор Base64

Это даст тот же результат для тех же значений, поскольку закодированное значение основано на записях, а не на ссылке на объект.

  static String getIdentifier(String[] array)
 {
    String all="";
    for (String s : array)
        all =s;
    return Base64.getEncoder().encodeToString(all.getBytes());
 }
 

И тогда вы могли бы:

 Map<String, String[]> arrayMap= new HashMap<>();
String[] items = new String[]{"apple","pear", "banana"}; // *[1234] 
action.add(items);
arrayMap.put(getIdentifier(items), items); // id = QUJDYWFh
//....
//Directly finding the twin will fail
String[] toSearch = new String[]{"apple","pear", "banana"}; // *[1556]
System.out.println(action.contains(toSearch)); // false

//But if we get the identifier based on the values
String arrId = getIdentifier(toSearch); // id = QUJDYWFh
System.out.println(action.contains(arrayMap.get(arrId)));  //true

//arrayMap.get(arrId)->  *[1234]
//.....
 

Имя.

Выберите представительное имя и используйте его в качестве идентификатора

 Map<String, String[]> arrayMap= new HashMap<>();
String[] items = new String[]{"apple","pear", "banana"};
action.add(items);
arrayMap.put("fruits", items);
//...
System.out.println(action.contains(arrayMap.get("fruits"))); // true  
    
 

Комментарии:

1. The issue here is that if you want to search for an specific array afterwards, you'd lose the references and searching an item wouldn't be possible, not even replicating the array with the same exact values. Супер странно. Где я могу прочитать больше об этом?

2. Это именно то, что происходит в вашем вопросе. Вы знаете, какие значения, вы реплицируете массив по точкам, и все равно сообщает вам, что он его не содержит. Это потому, что хэш-код вашего первого массива равен 1234, а второго — 1554 (упрощенный). Даже при одинаковых значениях это разные объекты.

3. String[] copy = items.clone() при вызове items.equals(copy) результат будет false . Почему? Протестируйте его. System.out.println(copy.hashCode()); и System.out.println(items.hashCode()); не тот же хэш-код, даже для клона.

4. @JJ123 dzone.com/articles/object-identity-and-equality-in-java

Ответ №4:

Согласно JavaDocs, метод «contains» использует методы «equals» и «hashCode», чтобы проверить, содержится ли объект.

Наводящий вопрос: знаете ли вы, какова реализация «equals» для массивов?

Проверьте это, и вы, вероятно, поймете результат выполнения вашего кода (подсказка: ==).

Как сказал «Корабль на воздушной подушке, полный угрей», лучшим дизайном будет использование списка некоторой коллекции, которую вы понимаете / контролируете, это методы «equals» и «hashCode».