서로 다른 두 목록에 정확히 동일한 요소가 포함되어 있는지 확인하는 간단한 방법은 무엇입니까?
표준 Java 라이브러리에서 두 List에 정확히 동일한 요소가 포함되어 있는지 확인하는 가장 간단한 방법은 무엇입니까?
두 List가 동일한 인스턴스인지 여부는 중요하지 않으며 List의 type 매개 변수가 다른 경우에도 중요하지 않습니다.
예 :
List list1
List<String> list2;
// ... construct etc
list1.add("A");
list2.add("A");
// the function, given these two lists, should return true
내가 아는 얼굴에 나를 쳐다 보는 무언가가있을 것입니다 :-)
편집 : 명확히하기 위해 정확한 요소와 요소 수를 순서대로 찾고있었습니다.
순서에 관심이 있다면 equals 메소드를 사용하십시오.
list1.equals(list2)
javadoc에서 :
지정된 객체와이리스트가 동일한 지 어떤지를 비교합니다. 지정된 객체도 목록이고 두 목록의 크기가 동일하고 두 목록의 모든 해당 요소 쌍이 동일한 경우에만 true를 반환합니다. ((e1 == null? e2 == null : e1.equals (e2)) 인 경우 두 요소 e1과 e2는 같습니다.) 즉, 동일한 순서로 동일한 요소를 포함하는 두 목록은 동일하도록 정의됩니다. . 이 정의는 equals 메소드가 List 인터페이스의 다른 구현에서 올바르게 작동하도록합니다.
순서와 무관하게 확인하려면 모든 요소를 세트로 복사하고 결과 세트에서 equals를 사용할 수 있습니다.
public static <T> boolean listEqualsIgnoreOrder(List<T> list1, List<T> list2) {
return new HashSet<>(list1).equals(new HashSet<>(list2));
}
이 방법의 한계는 순서를 무시할뿐만 아니라 중복 요소의 빈도도 무시한다는 것입니다. 예를 들어, list1
""A ","B ","A "]이고 list2
" "A", "B", "B"] 인 경우 Set
접근 방식은 동일하다고 간주합니다.
순서에 민감하지 않지만 복제 빈도에 민감한 경우 다음 중 하나를 수행 할 수 있습니다.
- 이 질문에서 다른 질문에 대한 답변 처럼 두 목록 (또는 사본)을 비교하기 전에 정렬하십시오.
- 또는 모든 요소를 멀티 세트에 복사
나는 자신의 대답을 보증한다고 생각하는 의견에 많은 것을 게시했습니다.
모두가 여기에서 말했듯이 equals () 사용은 순서에 달려 있습니다. 주문에 신경 쓰지 않으면 3 가지 옵션이 있습니다.
옵션 1
사용하십시오 containsAll()
. 이 옵션은 최악의 경우 성능을 제공하기 때문에 이상적이지 않습니다 .O (n ^ 2).
옵션 2
이에 대한 두 가지 변형이 있습니다.
2a) 목록의 순서를 유지하는 데 신경 쓰지 않는다면 Collections.sort()
두 목록 모두에서 사용 하십시오. 그런 다음을 사용하십시오 equals()
. 두 가지 정렬을 수행 한 다음 O (n) 비교를 수행하기 때문에 이것은 O (nlogn)입니다.
2b) 목록 순서를 유지해야하는 경우 두 목록을 먼저 복사 할 수 있습니다. 그런 다음 복사 된 목록 모두에서 솔루션 2a 를 사용할 수 있습니다 . 그러나 복사 비용이 매우 비싸면 매력적이지 않을 수 있습니다.
이것은 다음으로 이어진다 :
옵션 3
요구 사항이 파트 2b 와 동일 하지만 복사 비용이 너무 비싼 경우 TreeSet을 사용하여 정렬을 수행 할 수 있습니다. 각 목록을 자체 TreeSet에 덤프하십시오. 세트로 정렬되며 원래 목록은 그대로 유지됩니다. 그런 다음 equals()
두 TreeSet
s 에서 비교를 수행하십시오 . TreeSets
들에서 O (nlogn) 시간을 구축 할 수 있고,이 equals()
O (N)이다.
선택해라 :-).
편집 : 나는 Laurence Gonsalves가 지적한것과 동일한 경고를 거의 잊었습니다. TreeSet 구현은 중복을 제거합니다. 중복에 관심이 있다면 일종의 정렬 된 다중 집합이 필요합니다.
Apache Commons Collections를 사용하고 있거나 사용하기를 좋아하는 경우 CollectionUtils.isEqualCollection 을 사용할 수 있습니다. "주어진 Collections가 정확히 동일한 카디널리티를 가진 동일한 동일한 요소를 포함하는 경우 true를 반환합니다."
파티에 매우 늦었지만이 null 안전 검사를 추가하고 싶었습니다.
Objects.equals(list1, list2)
나는 이것이 오래된 스레드라는 것을 알고 있지만 다른 대답은 내 유스 케이스를 완전히 해결하지 못했습니다 (구아바 멀티 세트가 똑같이 할 수도 있지만 여기에는 예가 없습니다). 내 서식을 변명 해주세요. 나는 여전히 스택 교환에 게시하는 것이 처음입니다. 또한 오류가 있으면 알려주세요
당신이 말할 수 있습니다 List<T>
A와 List<T>
B를하고 그들이 다음과 같은 조건과 동일한 경우 확인하려면 :
1) O (n) 예상 실행 시간
2) 평등은 다음과 같이 정의됩니다. a 또는 b의 모든 요소에 대해 a에서 요소가 발생하는 횟수는 b에서 요소가 발생하는 횟수와 같습니다. 요소 평등은 T.equals ()로 정의됩니다
private boolean listsAreEquivelent(List<? extends Object> a, List<? extends Object> b) {
if(a==null) {
if(b==null) {
//Here 2 null lists are equivelent. You may want to change this.
return true;
} else {
return false;
}
}
if(b==null) {
return false;
}
Map<Object, Integer> tempMap = new HashMap<>();
for(Object element : a) {
Integer currentCount = tempMap.get(element);
if(currentCount == null) {
tempMap.put(element, 1);
} else {
tempMap.put(element, currentCount+1);
}
}
for(Object element : b) {
Integer currentCount = tempMap.get(element);
if(currentCount == null) {
return false;
} else {
tempMap.put(element, currentCount-1);
}
}
for(Integer count : tempMap.values()) {
if(count != 0) {
return false;
}
}
return true;
}
우리가 해시 맵에 O (2 * n) 삽입을하고 O (3 * n) 해시 맵 선택을 수행하기 때문에 실행 시간은 O (n)입니다. 이 코드를 완전히 테스트하지 않았으므로주의하십시오 :)
//Returns true:
listsAreEquivelent(Arrays.asList("A","A","B"),Arrays.asList("B","A","A"));
listsAreEquivelent(null,null);
//Returns false:
listsAreEquivelent(Arrays.asList("A","A","B"),Arrays.asList("B","A","B"));
listsAreEquivelent(Arrays.asList("A","A","B"),Arrays.asList("A","B"));
listsAreEquivelent(Arrays.asList("A","A","B"),null);
순서가 같을 필요는 없지만 동일한 값의 배수를 지원하는이 버전을 사용해보십시오. 각 값의 수량이 같은 경우에만 일치합니다.
public boolean arraysMatch(List<String> elements1, List<String> elements2) {
// Optional quick test since size must match
if (elements1.size() != elements2.size()) {
return false;
}
List<String> work = newArrayList(elements2);
for (String element : elements1) {
if (!work.remove(element)) {
return false;
}
}
return work.isEmpty();
}
두 목록이 요소는 동일하지만 순서가 다른 경우에 대한 솔루션 :
public boolean isDifferentLists(List<Integer> listOne, List<Integer> listTwo) {
if(isNullLists(listOne, listTwo)) {
return false;
}
if (hasDifferentSize(listOne, listTwo)) {
return true;
}
List<Integer> listOneCopy = Lists.newArrayList(listOne);
List<Integer> listTwoCopy = Lists.newArrayList(listTwo);
listOneCopy.removeAll(listTwoCopy);
return CollectionUtils.isNotEmpty(listOneCopy);
}
private boolean isNullLists(List<Integer> listOne, List<Integer> listTwo) {
return listOne == null && listTwo == null;
}
private boolean hasDifferentSize(List<Integer> listOne, List<Integer> listTwo) {
return (listOne == null && listTwo != null) || (listOne != null && listTwo == null) || (listOne.size() != listTwo.size());
}
Tom의 대답은 훌륭합니다. 그의 대답에 전적으로 동의합니다!
이 질문의 흥미로운 측면은 List
유형 자체와 고유 한 순서 가 필요한지 여부 입니다.
그렇지 않은 경우 확인하려는 시점이 아니라 삽입 시점에 정렬 된 데이터 구조를 전달할 때 유연성이 떨어지 Iterable
거나 저하 될 수 있습니다 Collection
.
순서가 중요하지 않으며 중복 요소가없는 경우을 사용하십시오 Set
.
순서가 중요하지만 삽입 시간에 의해 정의되고 중복이없는 경우 LinkedHashSet
TreeSet과 같지만 삽입 시간에 따라 정렬됩니다 (중복은 계산되지 않음). 이것은 또한 당신에게 O(1)
상각 액세스를 제공합니다 O(log n)
.
List의 equals 메소드가이를 수행하고 List가 정렬되므로 두 List가 동일한 순서로 동일한 요소를 가져야합니다.
return list1.equals(list2);
샘플 코드 :
public static '<'T'>' boolean isListDifferent(List'<'T'>' previousList,
List'<'T'>' newList) {
int sizePrevoisList = -1;
int sizeNewList = -1;
if (previousList != null && !previousList.isEmpty()) {
sizePrevoisList = previousList.size();
}
if (newList != null && !newList.isEmpty()) {
sizeNewList = newList.size();
}
if ((sizePrevoisList == -1) && (sizeNewList == -1)) {
return false;
}
if (sizeNewList != sizePrevoisList) {
return true;
}
List n_prevois = new ArrayList(previousList);
List n_new = new ArrayList(newList);
try {
Collections.sort(n_prevois);
Collections.sort(n_new);
} catch (ClassCastException exp) {
return true;
}
for (int i = 0; i < sizeNewList; i++) {
Object obj_prevois = n_prevois.get(i);
Object obj_new = n_new.get(i);
if (obj_new.equals(obj_prevois)) {
// Object are same
} else {
return true;
}
}
return false;
}
Laurence의 답변 외에도 null 안전을 원한다면 :
private static <T> boolean listEqualsIgnoreOrder(List<T> list1, List<T> list2) {
if (list1 == null)
return list2==null;
if (list2 == null)
return list1 == null;
return new HashSet<>(list1).equals(new HashSet<>(list2));
}
list1.equals(list2);
목록에 사용자 정의 클래스 MyClass가 포함 된 경우이 클래스는 equals
함수 를 대체해야합니다 .
class MyClass
{
int field=0;
@0verride
public boolean equals(Object other)
{
if(this==other) return true;
if(other==null || !(other instanceof MyClass)) return false;
return this.field== MyClass.class.cast(other).field;
}
}
참고 :가 아닌 java.util.Set에서 equals를 테스트 java.util.List
하려면 객체가 hashCode
함수 를 재정의해야합니다 .
List.equals ()
http://java.sun.com/j2se/1.5/docs/api/java/util/List.html#equals(java.lang.Object)
Apache의 org.apache.commons.collections 라이브러리를 사용할 수 있습니다. http://commons.apache.org/collections/apidocs/org/apache/commons/collections/ListUtils.html
public static boolean isEqualList(java.util.Collection list1,
java.util.Collection list2)
두 목록이 모두 널이 아닌지 확인하십시오. 크기가 다르면이 목록이 동일하지 않습니다. 목록의 요소를 키로 구성하고 그 반복을 값으로 구성하여 맵을 작성하고 맵을 비교하십시오.
가정, 두 목록이 모두 null 인 경우 가정합니다.
private boolean compareLists(List<?> l1, List<?> l2) {
if (l1 == null && l2 == null) {
return true;
} else if (l1 == null || l2 == null) {
return false;
}
if (l1.size() != l2.size()) {
return false;
}
Map<?, Integer> m1 = toMap(l1);
Map<?, Integer> m2 = toMap(l2);
return m1.equals(m2);
}
private Map<Object, Integer> toMap(List<?> list) {
//Effective size, not to resize in the future.
int mapSize = (int) (list.size() / 0.75 + 1);
Map<Object, Integer> map = new HashMap<>(mapSize);
for (Object o : list) {
Integer count = map.get(o);
if (count == null) {
map.put(o, 1);
} else {
map.put(o, ++count);
}
}
System.out.println(map);
return map;
}
이러한 객체에 대해 메소드 등가를 올바르게 정의해야합니다. https://stackoverflow.com/a/24814634/4587961
사용중인 구체적인 List 클래스에 따라 다릅니다. 추상 클래스 AbstractCollection에는 다른 컬렉션 (List는 컬렉션 임)을 취하는 containsAll (Collection)이라는 메서드가 있습니다.
이 컬렉션에 지정된 컬렉션의 모든 요소가 포함되어있는 경우에 true를 리턴합니다.
따라서 ArrayList가 전달되면이 메소드를 호출하여 정확히 동일한 지 확인할 수 있습니다.
List foo = new ArrayList();
List bar = new ArrayList();
String str = "foobar";
foo.add(str);
bar.add(str);
foo.containsAll(bar);
containsAll ()의 이유는 두 번째 목록에서 일치하는 항목을 찾는 첫 번째 목록을 반복하기 때문입니다. 따라서 순서가 맞지 않으면 equals ()가 선택하지 않습니다.
편집 : 나는 다양한 옵션을 제공하는 상각 실행 시간에 대해 여기에 의견을 남기고 싶습니다. 러닝 타임이 중요합니까? 확실한. 고려해야 할 유일한 것입니까? 아니.
목록의 모든 단일 요소를 다른 목록으로 복사하는 데 시간이 걸리고 메모리를 많이 차지합니다 (사용중인 메모리를 두 배로 늘림).
따라서 JVM의 메모리가 중요하지 않은 경우 (일반적으로 있어야 함) 여전히 모든 요소를 두 목록에서 두 개의 TreeSet으로 복사하는 데 걸리는 시간을 고려해야합니다. 입력되는 모든 요소를 정렬한다는 것을 기억하십시오.
마지막 조언은? 여기에서 올바른 결정을 내리기 전에 데이터 세트와 데이터 세트에있는 요소 수, 데이터 세트의 각 오브젝트의 크기를 고려해야합니다. 그들과 함께 놀면서 각 길을 하나씩 만들고 어느 쪽이 더 빨리 달리는지 확인하십시오. 좋은 운동입니다.
'Programing' 카테고리의 다른 글
IntelliJ IDEA에서 맞춤법 검사를 사용하지 않도록 설정 (0) | 2020.04.18 |
---|---|
Android는 현재 타임 스탬프를 가져 옵니까? (0) | 2020.04.18 |
코드의 maven pom.xml에서 버전 검색 (0) | 2020.04.18 |
Nodejs가 Windows에서 설치된 모듈을 찾을 수 없습니다 (0) | 2020.04.18 |
Gulp 설치 후 : "gulp '명령이 없습니다" (0) | 2020.04.18 |