java.util.Set에 get (int index)이없는 이유는 무엇입니까?


237

나는 좋은 이유가 있다고 확신하지만 누군가 java.util.Set인터페이스가 부족한 이유 get(int Index)또는 유사한 get()방법을 설명해 주 시겠습니까?

세트가 물건을 넣는 데는 좋은 것 같지만 단일 항목을 검색하는 우아한 방법을 찾을 수 없습니다.

첫 번째 항목을 원한다는 것을 알고 있다면을 사용할 수 set.iterator().next()있지만 그렇지 않으면 특정 색인에서 항목을 검색하기 위해 Array로 캐스팅해야합니까?

세트에서 데이터를 검색하는 적절한 방법은 무엇입니까? (반복자를 사용하지 않는 것)

API에서 제외되었다는 사실은 이것을하지 않는 좋은 이유가 있음을 의미합니다. 누군가 나를 기쁘게 할 수 있습니까?

편집하다: 여기에 매우 훌륭한 답변과 "더 많은 맥락"이라고 말하는 몇 가지. 특정 시나리오는 dbUnit 테스트였습니다. 여기서 쿼리에서 반환 된 집합에 항목이 하나만 있다고 합리적으로 주장 할 수 있었고 해당 항목에 액세스하려고했습니다.

그러나 질문은 더 집중되어 있으므로 시나리오 없이도 더 유효합니다.

설정 및 목록의 차이점은 무엇입니까 .

아래 환상적인 답변에 감사드립니다.


1
왜 색인으로 세트에서 요소를 얻습니까? 집합을 정렬 된 배열로 사용하려고합니까?
MSN

여기의 특정 인스턴스는 최대 절전 모드 호출에서 반환 된 Set에 대한 dbUnit 테스트입니다. 필자의 테스트에서는 반환 된 객체가 특정 순서대로 있다고 가정하는 것이 합리적입니다. 내 IDataSet 때문에 객체를 설정했습니다. 일반적인 사례는 아니지만 API에 대한 궁금증이 생깁니다.
Marty Pitt

1
특정 순서로 항목을 추가한다고해서 사용자 정의 Set 구현을 사용하지 않는 한 그대로 유지되는 것은 아닙니다.
마이클 마이어스

1
"첫 번째 항목을 원하면 set.iterator (). next ()를 사용할 수 있습니다."-이 줄은 실제로 의미가 없습니다. "내가 첫 번째 항목을 원한다는 것을 알고 있다면 첫 번째 항목의 구현 정의에 따라 할 수 있습니다 ..."라고 말하고 있습니다. 세트 자체는 순서가 없으므로 인덱스 액세스는 의미가 없습니다. 이제 ArrayListSet이 있다면 더 의미가있을 것입니다 ( "List"로 캐스트하고 행복합니다). 아마도 당신은 질문에 더 많은 맥락을 줄 수 있습니까?
jsight

순서가 정렬되지 않았습니다! 특정 구현은 있지만 일부 구현은 특정 방식으로 명시 적으로 정렬됩니다.
reinierpost

답변:


176

세트에는 주문이 없기 때문입니다. 일부 구현은 (특히 java.util.SortedSet인터페이스를 구현하는 ) 구현 이지만 집합의 일반적인 속성은 아닙니다.

이 방법으로 세트를 사용하려는 경우 대신 목록을 사용하는 것이 좋습니다.


10
@ matt b : 아니오, 나는 그것을 고려해야한다고 생각합니다. 생각하는 것이 좋습니다. ;)
Michael Myers

10
그것을 고려한 다음에하십시오.
Joe Phillips

21
"고려"는 올바른 문구입니다. 두 가지 가능한 문제가 있습니다. (a) 다른 것을 사용해야 할 때 세트를 사용하고 있거나 (b) 세트를 사용하여 지원하지 않지만 다른 방식으로 할 수있는 세트로 작업하려고합니다. 이 중 어떤 경우인지 고려 하는 것이 좋습니다 .
kenj0418

6
더 간단한 대답은 정렬 된 세트를 사용하는 것입니다. (나는 세트를 선택하는 동안 독창성이 역할을한다고 가정합니다). 그러나 SortedSet이 주문되었으므로 API에 get 메소드가없는 이유는 무엇입니까?
uncaught_exceptions

5
@HDave : 아니요, 데이터 구조의 여러 구현이 속성을 공유한다고해서 데이터 구조 자체의 속성이되지는 않습니다. 일반적으로 사용되는 3 가지 List 구현 (ArrayList 및 Vector) 중 2 개는 랜덤 액세스이지만 랜덤 액세스를 List의 속성으로 만들지는 않습니다.
마이클 마이어스

74

실제로 이것은 Object-Relational Mapping을 사용하는 JavaEE 애플리케이션을 작성할 때 반복되는 질문입니다 (예 : 최대 절전 모드). 그리고 여기에 대답 한 모든 사람들로부터 Andreas Petersson은 실제 문제를 이해하고 그에 대한 정답을 제시 한 유일한 사람입니다 .Java에는 UniqueList가 없습니다! 또는 OrderedSet 또는 IndexedSet이라고도합니다.

Maxwing 은이 유스 케이스 (주문하고 고유 한 데이터가 필요함)를 언급했으며 SortedSet을 제안했지만 이것이 Marty Pitt가 실제로 필요한 것은 아닙니다.

이 "IndexedSet"은 SortedSet과 동일하지 않습니다.-SortedSet에서 요소는 비교기를 사용하여 (또는 "자연적인"순서를 사용하여) 정렬됩니다.

그러나 대신 LinkedHashSet (다른 사람들도 제안)에 더 가깝거나 존재하지 않는 "ArrayListSet"에 더 가깝습니다. 요소가 삽입 된 순서와 동일한 순서로 반환되도록하기 때문입니다.

그러나 LinkedHashSet은 인터페이스가 아닌 구현입니다! 필요한 것은 IndexedSet (또는 ListSet, OrderedSet 또는 UniqueList) 인터페이스입니다! 이를 통해 프로그래머는 특정 순서를 가지고 중복되지 않은 요소 컬렉션이 필요하다고 지정한 다음 구현 (예 : Hibernate에서 제공하는 구현)으로 인스턴스화 할 수 있습니다.

JDK는 오픈 소스이므로이 인터페이스는 Java 7에 포함될 것입니다.


3
가능한 한 큰 대답이지만 그 동안 우리는 무엇을합니까?
HDave

당연히 그렇지. 전에는 최대 절전 모드에서 manytomany 및 onetomany ORM으로 list를 사용했습니다. 3 개 이상의 관련 엔터티를 포함하는 왼쪽 조인 쿼리에서 문제가 발생하여 예외가 발생했습니다. 자세한 내용은 여기 ( jroller.com/eyallupu/entry/… ) 를 참조하십시오 . 이 문제를 해결하려면 ORM 맵핑 콜렉션으로 설정을 사용해야합니다. 솔직히 말하면 set은 프로그래밍에서 액세스하는 데 편리하지 않으며 주문 컬렉션이 필요할 때 편리합니다. 우리가 정말 필요가 소린 포스텔 니쿠는 SORT 및 UNIQUE 말처럼 "indexedset"무엇
horaceman

2
Apache Commons Collections에는 ListOrderedSet7 년 전 OP가 필요했던 것이 있습니다 (그리고 오늘 필요했습니다).
Paul

@Paul : 그것은 실제로 정말 좋아 보이는 것입니다. 불행히도 여전히 3 가지 단점이 있습니다. 1) 인터페이스가 아닌 클래스입니다. 2) JDK에 없습니다. 3) Hibernate 쿼리가 반환하는 것이 아닙니다.
Sorin Postelnicu 2016 년

네,하지만 그 3 가지 주요 단점 외에는 완벽합니다! 내가 오프 키가 - :)에서 내가 질문에 대한 내 댓글을 게시하지 답을해야 회고 What is needed is an IndexedSet (or ListSet, or OrderedSet, or UniqueList)...무시 ...interface. 미안합니다!
Paul

29

mmyers 'answer 에서 언급되지 않은 한 점만 추가하면 됩니다.

첫 번째 항목이 필요하다는 것을 알고 있다면 set.iterator (). next ()를 사용할 수 있지만 그렇지 않으면 특정 인덱스에서 항목을 검색하기 위해 Array로 캐스팅해야합니까?

세트에서 데이터를 검색하는 적절한 방법은 무엇입니까? (반복자를 사용하지 않는 것)

또한 SortedSet인터페이스 (가장 일반적인 구현은 TreeSet)에 익숙해 져야 합니다.

SortedSet은 요소의 자연 순서 에 따라 또는 일부를 사용하여 정렬 된 집합 (즉, 요소가 고유 한 요소)입니다 Comparator. first()last()방법을 사용하여 첫 번째 항목과 마지막 항목에 쉽게 액세스 할 수 있습니다 . A SortedSet는 컬렉션을 복제하지 않고 특정 방식으로 주문해야 할 때 가끔 편리합니다.

편집 : 요소가 삽입 순서대로 유지되는 세트가 필요하면 (List와 유사)를 살펴보십시오 LinkedHashSet.


나는 LinkedHashSet을 좋아한다. 그러나 그렇습니다. +1
Michael Myers

고마워, 나는 대답을 조금 조정했다. (TreeSet의 일부 측면이 LinkedHashSet의 측면과 혼동 된 것 같습니다.)
Jonik

25

이런 종류의 세트는 세트를 사용해야 할 때와 목록을 사용해야 할 때 문제가됩니다. 일반적으로 조언은 다음과 같습니다.

  1. 주문한 데이터가 필요한 경우 목록을 사용하십시오.
  2. 고유 한 데이터가 필요한 경우 세트를 사용하십시오.
  3. 둘 다 필요한 경우 SortedSet (비교자가 정렬 한 데이터의 경우) 또는 OrderedSet / UniqueList (삽입이 정렬 된 데이터의 경우)를 사용하십시오. 불행히도 Java API에는 아직 OrderedSet / UniqueList가 없습니다.

자주 나타나는 네 번째 경우는 둘 다 필요하지 않다는 것입니다. 이 경우 일부 프로그래머는 목록과 함께 있고 일부는 세트와 함께 있습니다. 개인적으로 나는 주문없이 목록으로 목록을 보는 것이 매우 해롭다는 것을 알았습니다. 왜냐하면 그것은 정말로 다른 짐승이기 때문입니다. 고유성을 설정하거나 평등을 설정하지 않는 한 항상 목록을 선호하십시오.


2
구체적이지 않은 경우 Collection <T> 또는 Iterable <T>를 수락하고 List로 초기화하십시오.
Andreas Petersson

이것은 백이나 멀티 셋입니다. 그러나 Java는이를 지원하지 않습니다. 그들은 Collection <T>를 직접 사용해야한다고 말합니다.
기계 달팽이

4. 고유하지 않은 데이터가 필요하며 주문에 신경 쓰지 않습니다. 세트를 사용할 수 없습니다. List, Bag 또는 Multiset이 작동합니다.
Andrew Gallasch 2016 년

17

아무도이 방법으로 정확하게 철자를했는지 확실하지 않지만 다음을 이해해야합니다.

세트에 "첫 번째"요소가 없습니다.

다른 사람들이 말했듯이 세트에는 주문이 없기 때문입니다. 집합은 구체적으로 순서를 포함하지 않는 수학적 개념입니다.

물론 컴퓨터는 실제로 메모리에 주문되지 않은 물건의 목록을 유지할 수 없습니다. 주문이 필요합니다. 내부적으로는 배열 또는 연결된 목록 또는 무언가입니다. 그러나 당신은 그것이 무엇인지 정말로 알지 못하며, 실제로 첫 번째 요소가 없습니다. "먼저"나오는 요소는 우연히 그런 식으로 나오며 다음 번에는 처음이 아닐 수도 있습니다. 특정 첫 번째 요소를 "보증"하기위한 단계를 밟아도 한 세트의 특정 구현에 대해 올바르게 이해했기 때문에 여전히 우연히 나옵니다. 다른 구현은 당신이 한 일에서 그렇게 작동하지 않을 수 있습니다. 그리고 실제로 사용하고있는 구현과 생각하는 것을 모를 수도 있습니다.

사람들은이 모든 것에 부딪칩니다. 그만큼. 시각. RDBMS 시스템으로 이해하지 못합니다. RDBMS 조회는 레코드 세트를 리턴합니다. 이것은 수학에서와 같은 유형의 집합입니다.이 경우에만 항목은 레코드 인 정렬되지 않은 항목 모음입니다. ORDER BY 절을 사용하지 않으면 RDBMS 쿼리 결과의 순서가 전혀 보장되지 않지만 사람들이 항상 가정하고 데이터 또는 코드의 모양이 약간 변경되고 쿼리 최적화 프로그램이 작동 할 때 언젠가는 스스로 트립됩니다. 다른 방식으로 갑자기 결과가 원하는 순서대로 나오지 않습니다. 이들은 일반적으로 데이터베이스 클래스에서 (또는 설명서 또는 자습서를 읽을 때) 설명하지 않았을 때 쿼리 결과에 보장 된 순서가 없다는 데주의를 기울이지 않은 사람들입니다.


물론, 순서는 일반적으로 코드가 너무 느리면 코드가 프로덕션에 들어가 자마자 변경되므로 쿼리 속도를 높이기 위해 인덱스를 추가합니다. 이제 코드가 빠르게 실행되지만 잘못된 답변을 제공합니다. 운이 좋으면 3-4 일 동안 아무도 눈치 채지 못합니다. 운이 좋지 않다면 아무도 한 달 동안 통지하지 않습니다.
TMN

나는 그가 그것을 놓쳤다 고 생각하지 않습니다 (아마도 그는 표기법이 어색했을 수도 있습니다). 그는 세트에서 첫 번째 요소를 원하지 않고 세트에서 임의의 요소를 원합니다. Setis 이후로 임의의 요소를 제공 할 수 있습니다 Iterable.
Elazar Leibovich

인덱스로 get (index)에 대해 이야기하고 있습니다. 평등에 의한 get (Object)은 어떻습니까?
Kumar Manish

10

일부 데이터 구조가 표준 Java 콜렉션에서 누락되었습니다.

가방 (세트와 같지만 요소를 여러 번 포함 할 수 있음)

UniqueList (순서 목록, 각 요소는 한 번만 포함 할 수 있음)

이 경우 고유 목록이 필요할 것 같습니다.

유연한 데이터 구조가 필요한 경우 Google 컬렉션에 관심이있을 수 있습니다.


1
Guva는 "UniqueList"를 제공합니까?
Mike Rylander

아니오, 그러나 유사한 특성을 가진 java.util.LinkedHashSet을 가질 수 있습니다.
Andreas Petersson '12

7

사실, Set 컬렉션의 정의에 따라 Set의 요소는 정렬되지 않습니다. 따라서 인덱스로 액세스 할 수 없습니다.

그러나 인덱스를 매개 변수로 제공하는 것이 아니라 찾고있는 객체와 동일한 객체를 사용하여 get (object) 메소드를 사용하지 않는 이유는 무엇입니까? 이런 식으로, 우리는 equal 메소드에 의해 사용되는 속성을 아는 것만으로 Set 내부의 요소 데이터에 접근 할 수 있습니다.


7

세트에서 인덱스별로 많은 랜덤 액세스를 수행하려는 경우 해당 요소의 배열보기를 얻을 수 있습니다.

Object[] arrayView = mySet.toArray();
//do whatever you need with arrayView[i]

그러나 두 가지 주요 단점이 있습니다.

  1. 전체 세트에 대한 배열을 작성해야하므로 메모리 효율적이지 않습니다.
  2. 세트가 수정되면보기가 더 이상 사용되지 않습니다.

5

Set은 고유성을 보장하지만 최적의 액세스 또는 사용 패턴에 대해서는 아무 것도 말하지 않기 때문입니다. 즉, 집합은 목록 또는 맵일 수 있으며 각 검색 특성은 매우 다릅니다.


5

집합에서 숫자 인덱스를 사용한다고 생각할 수있는 유일한 이유는 반복 때문입니다. 이를 위해

for(A a : set) { 
   visit(a); 
}

사실이 아닌 경우 임의의 요소에 액세스하는 것은 어떻습니까?
Jeremy Salwen

ㅋ. 좋은 지적 :) 그러나 그것은 오용되기 쉬운 경향이 있습니다.
휴고

3

인덱스를 통해 액세스 할 수 있는 정렬 된 세트를 실제로 원했던 상황에 부딪 쳤습니다 (인덱스로 정렬되지 않은 세트에 액세스하는 것은 다른 포스터와 일치합니다). 예를 들어 내가 아이들을 정렬하고 중복 된 아이들을 허용하지 않는 나무가 있습니다.

인덱스를 통해 액세스해야 인덱스를 표시하고 세트 속성이 중복을 효율적으로 제거하는 데 편리했습니다.

java.util 또는 Google 컬렉션에서 적합한 컬렉션을 찾지 못하면 직접 구현하는 것이 간단하다는 것을 알았습니다. 기본 아이디어는 인덱스를 통한 액세스가 필요할 때 SortedSet을 랩핑하고 목록을 작성하는 것입니다 (SortedSet이 변경되면 목록을 잊어 버리는 것). 래핑 된 SortedSet을 변경하고 목록에 액세스하는 것이 컬렉션 수명 기간 동안 분리 된 경우에만 효율적으로 작동합니다. 그렇지 않으면 자주 정렬되는 목록처럼 동작합니다 (예 : 너무 느림).

자녀 수가 많을수록 Collections.sort를 통해 정렬 한 목록보다 성능이 크게 향상되었습니다.


2

인덱스를 통해 2 개의 기본 데이터 구조에만 액세스 할 수 있습니다.

  • O(1)시간이 복잡한 인덱스를 통해 어레이 데이터 구조에 액세스하여 get(int index)작업을 수행 할 수 있습니다.
  • 연결 목록 데이터 구조는 색인을 통해 액세스 할 수도 있지만 O(n)시간이 복잡하여 get(int index)조작이 가능합니다.

Java에서는 Array 데이터 구조를 ArrayList사용하여 구현됩니다 .

상태 설정 데이터 구조는 일반적으로 통해 구현 될 수있다 해시 / HashMap의 또는 BalancedTree의 빠른 요소가 존재하고 존재하지 않는 요소를 추가할지 여부를 검출하기위한 데이터 구조, 보통 잘 구현 집합 달성 O(1)시간 복잡도 contains동작. Java HashSet에서 가장 일반적으로 사용되는 Set 구현은 HashMapAPI 를 호출 HashMap하여 구현 되며 연결된 목록과 함께 별도의 체인을 사용하여 구현됩니다 ( ArrayLinkedList .

이후 집합은 다른 데이터 구조를 통해 구현 될 수 있고, 더 없다 get(int index)그것을위한 방법.


핑거 트리 (Haskell의 Data.Sequence.lookup기능 참조 )는 인덱스를 통해 액세스 할 수 있으며 (중간 O(1)근처의 끝 O(log n)근처에서 더 정확하게 O(min(log(k), log(n-k)))) 이진 트리도 마찬가지입니다 (Haskell의 Data.Set.lookupIndex기능 참조 ). 따라서 "인덱스를 통해 2 개의 기본 데이터 구조 만 액세스 할 수 있습니다"라는 초기 주장이 올바르지 않습니다.
세미콜론

1

Set 인터페이스가 필요한 이유 인덱스 유형 가져 오기 호출이 없거나 first () 또는 last ()와 같이 훨씬 더 기본적인 것이없는 이유는 모호한 작업이므로 잠재적으로 위험한 작업이기 때문입니다. 메서드가 Set을 반환하고 first () 메서드를 호출하면 일반 Set이 순서를 보장하지 않는 경우 예상되는 결과는 무엇입니까? 결과 객체는 메소드를 호출 할 때마다 매우 다양 할 수 있으며 변경하는 라이브러리가 아래의 구현을 변경하고 모든 코드가 중단 될 때까지 잘못된 보안 감각에 빠지지 않을 수 있습니다. 특별한 이유가 없습니다.

여기에 나열된 해결 방법에 대한 제안이 좋습니다. 인덱스 액세스가 필요한 경우 목록을 사용하십시오. a) 순서에 대한 보장이 없으며 b) 후속 호출이나 다른 기본 구현으로 순서가 변경되지 않을 것이라는 보장이 없으므로 일반적인 Set과 함께 반복자 또는 toArray를 사용할 때는주의하십시오. 그 사이에 무언가가 필요한 경우 SortedSet 또는 LinkedHashSet이 원하는 것입니다.

// Set 인터페이스에 get-random-element가 있었으면 좋겠습니다.


1

java.util.Set정렬되지 않은 항목의 모음입니다. Set에 인덱스가없고 값만 추측 할 수 있기 때문에 Set에 get (int index)이 있으면 의미가 없습니다.

정말로 이것을 원한다면 Set에서 임의의 요소를 얻도록 메소드를 코딩하십시오.


0

넌 할 수있어 new ArrayList<T>(set).get(index)


Set의 List를, get (index)는 Set을 반환합니다. 오히려, 나는 사용했다 : new ArrayList<T>(t).get(0) 나는 인덱스에 의해 Set에서 특정 요소를 얻는 아이디어에 대한 반대가 있다고 생각한다. 그러나 Set에 size 1의 Set에 대해 Set의 유일한 요소에 쉽게 액세스 할 수있는 only () 멤버 함수가 있으면 좋을 것입니다. 이것은 앞서 언급 new ArrayList했거나for (Foo foo : foos) { return foo; }
Doug Moscrop

0

세트를 정렬하지 않아도되는 경우 인덱스 트리 맵 프로젝트를 살펴 보는 것이 좋습니다 .

향상된 TreeSet / TreeMap 은 색인을 통해 또는 요소의 색인을 가져 와서 요소에 대한 액세스를 제공합니다. 그리고 구현은 RB 트리에서 노드 가중치 업데이트를 기반으로합니다. 따라서 목록으로 반복하거나 백업하지 마십시오.


0

Set은 인터페이스이며 일부 구현 클래스는 HashSet, TreeSet 및 LinkedHashSet입니다. 후드 아래에서 HashMap을 사용하여 값을 저장합니다. HashMap은 순서를 유지하지 않기 때문에 인덱스별로 값을 가져올 수 없습니다.

HashMap은 키, 값 쌍을 저장하지만 Set 은하 지 않으므로 Set이 HashMap을 사용하는 방법을 생각해야합니다. 유효한 질문입니다. 내부적으로 Set에 요소를 추가하면 키가 Set에 입력하려는 요소이고 값이 더미 상수 인 HashMap이 유지됩니다. 다음은 add 함수의 내부 구현입니다. 따라서 HashMap의 모든 키는 동일한 상수 값을 갖습니다.

// Dummy value to associate with an Object in the backing Map
private static final Object PRESENT = new Object();

public boolean add(E e) {
    return map.put(e, PRESENT)==null;
}

모든 Set구현은 HashMap후드를 사용하여 값을 저장하고 있습니다. 그 주장을 입증 할 수 TreeSet있습니까?
greybeard

1
the keys in the HashMap will have the same constant value 의 키는 HashMap것이다 매핑 하나의 동일한 불변Object
수염이 희끗 희끗 한


-3

세트의 요소를 얻으려면 다음 중 하나를 사용합니다.

public T getElement(Set<T> set, T element) {
T result = null;
if (set instanceof TreeSet<?>) {
    T floor = ((TreeSet<T>) set).floor(element);
    if (floor != null && floor.equals(element))
    result = floor;
} else {
    boolean found = false;
    for (Iterator<T> it = set.iterator(); !found && it.hasNext();) {
    if (true) {
        T current = it.next();
        if (current.equals(element)) {
        result = current;
        found = true;
        }
    }
    }
}
return result;
}

기능은 질문에서 요구 한 것이 아닙니다. 우리는 가치가 아닌 색인이 필요합니다. 어쨌든 당신의 기능은 무엇입니까? 내부의 요소와 같으면 요소를 반환하는 것처럼 보입니다. contains ()하지 않는 것은 무엇입니까?
야누스 트롤 슨

T정의 된 곳은 어디 입니까? 왜 if (true)?
quantum.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.