본문

HashSet(JAVA)

반응형

# HashSet (Set : 순서유지x, 데이터중복허용x)

HashSet은 Set인터페이스를 구현한 가장 대표적인 컬렉션이며, Set인터페이스의 특징대로 HashSet은 중복된 요소를 저장하지 않는다.

HashSet에 새로운 요소를 추가할 때는 add메서드나 addAll메서드를 사용하는데, 만일 HashSet에 이미 저장되어 있는 요소와 중복된 요소를 추가하고자 한다면 이 메서드들은 false를 반환함으로써 중복된 요소이기 때문에 추가에 실패했다는 것을 알린다. 이러한 HashSet의 특징을 이용하면, 컬렉션 내의 중복된 요소들을 쉽게 제거할 수 있다.


ArrayList와 같이 List인터페이스를 구현한 컬렉션과 달리 HashSet은 저장순서를 유지하지 않으므로 저장순서를 유지하고자 한다면 LinkedHashSet을 사용해야한다.


Source 01) HashSetEx01.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package hashSetEx;
 
import java.util.HashSet;
import java.util.Set;
 
public class HashSetEx01 {
 
    public static void main(String[] args) {
 
  Object[] objArr = { "2""1"new Integer(1), "4""4""4""4","3","3" };
        Set set = new HashSet();
 
        for (int i = 0; i < objArr.length; i++) {
            set.add(objArr[i]); // HashSet에 objArr의 요소들을 저장한다.
        }
 
        System.out.println(set); // HashSet에 저장된 요소들을 출력한다.
    }
}
cs

Result)

1
[11234]        // 저장한 순서와 다르게 출력된다.
cs

결과에서 알 수 있듯이 중복된 값은 저장되지 않았다. '1'이 두 번 출력되었는데,둘 다 '1'로 보이기 때문에 구별이 안 되지만,
사실 하나는 String인스턴스이고 다른 하나는 Integer인스턴스로 서로 다른 객체이므로 중복으로 간주하지 않는다.

Set을 구현한 컬렉션 클래스는 List를 구현한 컬렉션 클래스와달리 순서를 유지하지 않기 때문에 저장한 순서와는 다르게 출력되었다.
만일 죽복을 제거하는 동시에 저장한 순서를 유지하고자 한다면 HashSet 대신 LinkedHashSet을 사용해야한다.


Source 02) HashSetEx02.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package hashSetEx;
 
import java.util.LinkedHashSet;
import java.util.Set;
 
public class HashSetEx02 {
 
    public static void main(String[] args) {
 
        Object[] objArr = { "2""1"new Integer(1), "4""4""4""4""3""3" };
        Set set = new LinkedHashSet(); // HashSet대신 LinkedHashSet을 사용한다.
 
        for (int i = 0; i < objArr.length; i++) {
            set.add(objArr[i]);
        }
 
        System.out.println(set);
 
    }
 
}
cs

Result)

1
[21143]        // 저장한 순서와 동일하게 출력된다.
cs


아래는 중복된 값은 저장되지 않는 HashSet의 성질을 이용해서 로또번호를 만드는 예제이다.

Source 03) HashSetEx03.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package hashSetEx;
 
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
 
public class HashSetEx03 {
 
    public static void main(String[] args) {
        Set set = new HashSet();
 
        for (int i = 0; set.size() < 6; i++) {
 
            int num = (int) (Math.random() * 45+ 1;    // random number 생성
            set.add(new Integer(num));    // random number 추가(대입)
        }
 
        List list = new LinkedList(set);    // LinkedList(Collection c)
        
  Collections.sort(list);    // Collections.sort(List list), 번호를 크기순으로 정렬
        System.out.println(list);
 
    }
}
cs

Result)

1
[1512162325]
cs

번호를 크기순으로 정렬하기위해서 Collections클래스의 sort(List list)를 사용했다. 
이 메서드는 인자로 List인터페이스 타입을 필요로 하기 때문에 LinkedList클래스의 생성자 LinkedList(Collection c)를 이용
HashSet에 저장된 객체들을 LinkedList에담아서 처리했다.
(※ Collections는 클래스이고, Collection은 인터페이스임에 주의하자.)


다음은 이름과 나이가 같으면 같은 사람으로 인식하도록 하는 예제이다.
Source 04) HashSetEx04.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
package hashSetEx;
 
import java.util.HashSet;
 
public class HashSetEx04 {
 
    public static void main(String[] args) {
        /*
         * HashSet의 add메서드는 새로운 요소를 추가하기 전에 기존에 저장된 요소와 같은 것인지 판별하기 위해 추가하려는 요소의
         * equals()와 hashCode()를 호출하기 때문에 equals()와 hashCode()를 목적에 맞게 오버라이딩해야 한다.
         */
 
        HashSet set = new HashSet();
 
        set.add("abc");
        set.add("abc");
        set.add(new Person("David"10));
        set.add(new Person("David"10));
        set.add(new Person("SungHan"20));
 
        System.out.println(set);
 
    }
}
 
class Person {
    String name;
    int age;
 
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
 
    public boolean equals(Object obj) {
        if (obj instanceof Person) {
            Person tmp = (Person) obj;
   
   /*
    * 두 인스턴스의 name과 age가 서로 같으면(주소값) true를 반환하도록 equals()를 오버라이딩했다.
*/
 
            return name.equals(tmp.name) && age == tmp.age;
        }
        return false;
    }
 
    // hashCode메서드 : 찾고자하는 값을 입력하면 그 값이 저장된 위치를 반환
    public int hashCode() {
        return (name + age).hashCode();
    }
 
    public String toString() {
        return name + ":" + age;
    }
 
}
cs

Result)
1
[abc, SungHan:20, David:10]
cs

HashSet의 add메서드는 새로운 요소를 추가하기 전에 기존에 저장된 요소와 같은 것인지 판별하기 위해
추가하려는 요소의 equals()와 hashCode()를 호출하기 때문에 equals()와 hashCode()를 목적에 맞게 오버라이딩해야 한다.
그래서 String클래스에서 같은 내용의 문자열에 대한 equals()의 호출결과가 true인 것과 같이, Person클래스에서도 두 인스턴스의 name과 age가 서로 같으면 true를 반환하도록 equals()를 오버라이딩했다.


다음 예제는 두 개의 HashSet에저장된 객체들을 비교해서 합집합, 교집합, 차집합을 구하는 방법을 보여준다.
사실 HashSet의 메서드를 호출하는 것만으로도 간단하게 합집합(addAll), 교집합(retainAll), 차집합(removeAll)을 구할 수 있지만,
직접 작성해 보는 것이 더 도움이 될 것 같아서 만들어보았다.

Source 05) HashSetEx05.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
package hashSetEx;
 
import java.util.HashSet;
import java.util.Iterator;
 
public class HashSetEx05 {
    static final int A_SIZE = 5;
    static final int B_SIZE = 8;
 
    public static void main(String[] args) {
        HashSet setA = new HashSet();
        HashSet setB = new HashSet();
        HashSet setHab = new HashSet();
        HashSet setKyo = new HashSet();
        HashSet setCha = new HashSet();
 
        for (int i = 1; i <= A_SIZE; i++) {
            setA.add(i);
        }
        System.out.println("A : " + setA);
 
        for (int i = 4; i <= B_SIZE; i++) {
            setB.add(i);
        }
        System.out.println("B : " + setB);
        System.out.println();
 
        // 교집합 메서드 :: A∩B
        Iterator it = setB.iterator();
        while (it.hasNext()) {
            Object tmp = it.next();
            if (setA.contains(tmp)) {
                setKyo.add(tmp);
            }
        }
 
        // 차집합 메서드 :: A-B
        it = setA.iterator();
        while (it.hasNext()) {
            Object tmp = it.next();
            if (!setB.contains(tmp)) {
                setCha.add(tmp);
            }
        }
 
        // 합집합 메서드 A∪B
        it = setA.iterator();
        while (it.hasNext()) {
            setHab.add(it.next());
        }
 
        it = setB.iterator();
        while (it.hasNext()) {
            setHab.add(it.next());
        }
 
        System.out.println("A∩B, 교집합 : " + setKyo);
        System.out.println("A-B, 차집합 : " + setCha);
        System.out.println("A∪B, 합집합 : " + setHab);
 
    }
 
}
cs

Result)
1
2
3
4
5
6
A : [12345]
B : [45678]
 
A∩B, 교집합 : [45]
A-B, 차집합 : [123]
A∪B, 합집합 : [12345678]
cs



출처 및 참고자료 : JAVA의정석(남궁성 저)


반응형

공유

댓글