본문 바로가기
CS(Computer Science)/20) 자바

자바를 자바 18 (Collection Framework (3)) : Iterator, Array, Comparable, Comparator

by tonyhan18 2020. 12. 3.
728x90

5. Iterator

자바에서 어떤 Collection이 존재할때 데이터를 읽어드리는 방법은 여러가지 이지만 앞에서부터 차례대로 읽어드릴 때 사용하는 것.

public interface Iterator<E> {
    ...
    boolean hasNext();
    E next();
    void remove();
}

정의는 위와 같이 되어 있다. 그래서 next를 부를 때마다 다음 원자로 넘어갈 수 있고 다음 인자가 존재하는지 화인하기 위해 hasNext 함수가 존재한다.

public interface Collection<E> {
    ...
    public Iterator iterator();
    ...
}

어떤 collection이 존재하면 iterator에 해당하는 interface가 호출된다.

Iterator: methods


함수는 위와 같이 제공된다. 이때 remove만 설명하면 가장 최근에 호출했던 element만 삭제된다.

사용법은 아래와 같다.

List<Integer> list = new ArrayList<Integer>();
Iterator<Integer> it = list.iterator();

while(it.hasNext()) {
    System.out.println(it.next());
}

위와 같이 그 다음원소가 있다면 계속해서 iterator 변수를 이용하여서 다음 변수로 이동하고 원하는 결과물을 출력한다.

이때 일반적으로 List<integer> 타입의 iterator을 우선적으로 사용한다. 왜냐하면 List Class는 ArrayList와 LinkedList의 상위 타입이기 때문에 나중에 ArrayList에서 LinkedList로 변경된다 하더라도 사용이 가능하기 때문이다.

Iterator: example 1

import java.util.*;
class Lecture {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<String>();
        list.add("1");
        list.add("2");
        list.add("3");
        list.add("4");
        list.add("5");

        // Iterator의 그 다음 원소를 계속해서 참조한다.
        Iterator<String> it =list.iterator();
        while(it.hasNext()) {
            System.out.print(it.next());
        }
    }
}

ListIterator

Iterator의 subclass로써 Iterator과의 차이점은 함수 몇가지가 추가된다는 점이다.

Iterator: example 2

import java.util.*;
class Lecture {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<String>();
        list.add("1");
        list.add("2");
        list.add("3");
        list.add("4");
        list.add("5");

        ListIterator<String> it = list.listIterator();
        while(it.hasNext()) {
            System.out.print(it.next());
        }
        System.out.println();

        // 이 부분이 차이점으로 이전에 있던 노드를 참조할 수 있다.
        ListIterator<String> it2 = list.listIterator();
        while(it2.hasNext()) {
            System.out.print(it2.next());
        }
        System.out.println();
        while(it2.hasPrevious()) {
            System.out.print(it2.previous());
        }
    }
}

6. Arrays

array와 관련된 method들을 제공해주는 역활을 수행한다.

copyOf : copyOf는 원래의 array로 부터 성분들을 복사해서 새로운 array를 만든다.
copyOfRange : (arr, 이상, 미만)의 자료를 복사한다.

int[] arr = {0, 1, 2, 3, 4};
// arr 처음부터 arr의 크기만큼 복사하겠다.
int[] arr2 = Arrays.copyOf(arr, arr.length); // arr2 is [0, 1, 2, 3, 4]
// arr 처음부터 3개만 복사
int[] arr3 = Arrays.copyOf(arr, 3); // arr3 is [0, 1, 2]
// arr 처음부터 7개만 복사 : 비는 부분은 0으로 초기화
int[] arr4 = Arrays.copyOf(arr, 7); // arr4 is [0, 1, 2, 3, 4, 0, 0]


int[] arr5 = Arrays.copyOfRange(arr, 2, 4); // arr5 is [2, 3] (index 4 is excluded)
int[] arr6 = Arrays.copyOfRange(arr, 0, 7); // arr6 is [0, 1, 2, 3, 4, 0, 0]

Arrays: methods

fill() : 어떠한 array를 일관된 값으로 채운다는 의미이다.
setAll() : generator function으로 만들어진 값들로 array를 채우겠다.

int[] arr = new int[5];
Arrays.fill(arr, 9); // arr is [9, 9, 9, 9, 9]

// () -> (int)(Math.random()*5)+1 : lambda experssion 형태로 압력
//()은 입력되는 것이 없다. -> 뒤쪽은 함수가 return 하는 값들이다. 여기에서는 (정수)(랜덤값*5)+1 의 랜덤값으로 반환하겠다는 의미이다.
Arrays.setAll(arr, () -> (int)(Math.random()*5)+1); // arr is [1, 5, 2, 1, 1]
// (random numbers between 1 and 5)

sort() : 오름차순으로 데이터가 정렬된다.
binarySearch(Array, 찾는 값) : Array를 search해서 찾는 값이 존재하는지 확인하는 binarySearch 알고리즘 방식의 함수이다. 대신 사용하기 위해서는 반드시 정렬이 되어 있어야 한다.

int[] arr = {3, 2, 0, 1, 4};
int idx = Arrays.binarySearch(arr, 2); // idx = -5 (wrong result)

Arrays.sort(arr);
System.out.println(Arrays.toString(arr));
int idx = Arrays.binarySearch(arr, 2); // idx = 2 (correct result)

toString(str) : Array를 String으로 만들어 준다.
equals(str1,str2) : 두 Array의 모든 element가 같은지 확인하다.(1차원)

int[] arr = {0, 1, 2, 3, 4};
int[][] arr2D = {{11, 12}, {21, 22}};

System.out.println(Arrays.toString(arr)); // [0, 1, 2, 3, 4]
System.out.println(Arrays.deepToString(arr2D)); // [[11, 12], [21, 22]]

deepEquals(str1,str2) : 두 Array의 모든 element가 같은지 확인한다.(2차원)

String[][] str2D = new String[][]{{"aaa","bbb"},{"AAA","BBB"}};
String[][] str2D2 = new String[][] {{"aaa","bbb"},{"AAA","BBB"}};

System.out.println(Arrays.equals(str2D, str2D2)); // false
System.out.println(Arrays.deepEquals(str2D, str2D2)); // true

Arrays: example

public static void main(String[] args) {
    int[] arr = {0, 1, 2, 3, 4};
    int[][] arr2D = {{11, 12, 13}, {21, 22, 23}};
    System.out.println("arr="+Arrays.toString(arr));
    System.out.println("arr2D="+Arrays.deepToString(arr2D));

    // copyOf
    int[] arr2 = Arrays.copyOf(arr, arr.length);
    int[] arr3 = Arrays.copyOf(arr, 3);
    int[] arr4 = Arrays.copyOf(arr, 7);

    //copyOfRange
    int[] arr5 = Arrays.copyOfRange(arr, 2, 4);
    int[] arr6 = Arrays.copyOfRange(arr, 0, 7);

    // toString
    System.out.println("arr2="+Arrays.toString(arr2));
    System.out.println("arr3="+Arrays.toString(arr3));
    System.out.println("arr4="+Arrays.toString(arr4));
    System.out.println("arr5="+Arrays.toString(arr5));
    System.out.println("arr6="+Arrays.toString(arr6));

    // fill
    int[] arr7 = new int[5];
    Arrays.fill(arr7, 9);
    System.out.println("arr7="+Arrays.toString(arr7));

    // setAll
    Arrays.setAll(arr7, i -> (int)(Math.random()*6)+1);
    System.out.println("arr7="+Arrays.toString(arr7));

    for(int i : arr7) {
        char[] graph = new char[i];
        Arrays.fill(graph, '*');
        System.out.println(new String(graph)+i);
    }

    // equals, deepEquals
    String[][] str2D = new String[][]{{"aaa","bbb"},{"AAA","BBB"}};
    String[][] str2D2 = new String[][]{{"aaa","bbb"},{"AAA","BBB"}};
    System.out.println(Arrays.equals(str2D, str2D2));
    System.out.println(Arrays.deepEquals(str2D, str2D2));

    // binarySearch
    char[] chArr = {'A', 'D', 'C', 'B', 'E'};
    System.out.println("chArr="+Arrays.toString(chArr));
    System.out.println("index of B="+Arrays.binarySearch(chArr, 'B'));

    // sort + binarySearch
    System.out.println("=== After sorting ===");
    Arrays.sort(chArr);
    System.out.println("chArr="+Arrays.toString(chArr));
    System.out.println("index of B="+Arrays.binarySearch(chArr, 'B'));
}

7. Comparable and Comparator

Comparable

Arrays나 Collection나 sort가 존재한다. 그런데 int나 float와 같은 경우 primitive trpse이기 때문에 비교가 가능해서 sort가 가능하다.

하지만 object와 같은 경우에 두 object가 비교가 불가능하기 때문에 sort가 불가능한 경우가 대다수이다.

그렇기 때문에 정리하면 성분들이 비교가 가능할때(comparable)만 가능하다.

그렇기 때문에 implements interface Comparable<T>의 타입 이 클래스는 실재로 interface Comparable을 구현한다.

Comparable: example

Comparable이라는 interface 안에는 compareTo라는 method가 존재

public final class Integer extends Number implements Comparable<Integer> {
    ...
    public int compareTo(Integer anotherInteger) {
        int thisVal = this.value;
        int anotherVal = anotherInteger.value;
        return (thisVal < anotherVal ? -1 : (thisVal == anotherVal ? 0 : 1));
    }
    ...
}

그렇기 때문에 compare을 상속받는 클래스에서는 compareTo를 구현해 주어야 한다. 내부를 살피어 보면 Integer을 상속받아서 비교를 하는 것을 확인할 수 있다.

이제 반환하는 것을 확인하면 -1이 반환된다면 thisVal이 더 작다는 것이고 만약 같다면 한 번더 비교를 해서 anotherVal이 더 크다면 1이 반환되게 된다.

// Comparable 클래스를 우선 상속하여 준다.
class Employee implements Comparable<Employee> {
    private String name;
    private int salary;
    public Employee(String name, int salary) { this.name = name; this.salary = salary; }
    public String getName() { return this.name; }
    public int getSalary() { return this.salary; }

    // 여기에서도 compareTo를 define 해준 것을 확인 할 수 있다.
    public int compareTo(Employee e) {
        if(this.salary > e.getSalary()) return -1;
        if(this.salary < e.getSalary()) return 1;
        return this.name.compareTo(e.getName());
    }
    public String toString() { return this.name + " " + this.salary; }
}

public class Lecture {
    public static void main(String[] args) {
        ArrayList<Employee> emplist = new ArrayList<Employee>();
        emplist.add(new Employee("Peter", 50000));
        emplist.add(new Employee("John", 100000));
        emplist.add(new Employee("Robert", 100000));

        // 여기에서 정렬을 하게 된다면 salary가 더 높은 사람 그 다음으로 이름을 비교할 것으로 예상이 된다.
        System.out.println(emplist);
        Collections.sort(emplist);
        System.out.println(emplist);
    }
}

Comparator

다른 방법으로 sort를 하기 원한다면 Comparator을 사용한다.

만약 아래 예시처럼 Arrays.sort를 사용하게 된다면 어떻게 될까?

public class Lecture {
    public static void main(String[] args) {
        String[] strArr = {"lion", "DOG", "TIGER", "cat"};
        System.out.println("strArr = " + Arrays.toString(strArr));

        Arrays.sort(strArr);
        System.out.println("strArr = " + Arrays.toString(strArr));
    }
}

분명 대문자 우선의 아스키코드 우선으로 출력이 될것이다.

그런데 우리가 원하는 것은 내림차순이라면 어떻게 해야 할까?

이것을 위해서 다음 클래스를 새롭게 선언해 준다.

class Descending<T> implements Comparator<T> {
    //o1과 o2를 비교하는 함수
    public int compare(T o1, T o2) {
        //Comparable의 subClass인지 확인후 type 변환
        if(o1 instanceof Comparable && o2 instanceof Comparable) {
            Comparable c1 = (Comparable)o1;
            Comparable c2 = (Comparable)o2;
            //내림차순으로 바꾸기
            return c1.compareTo(c2) * -1; // reverse order
        }
        return -1; // undefined
    }
}


실재 Comparator은 다음과 같이 구현이 되어 있다.

public static final Comparator<String> CASE_INSENSITIVE_ORDER = new CaseInsensitiveComparator();

private static class CaseInsensitiveComparator implements Comparator<String>, java.io.Serializable {
    private static final long serialVersionUID = 8575799808933029326L;
    public int compare(String s1, String s2) {
        byte v1[] = s1.value;
        byte v2[] = s2.value;
        if(s1.coder() == s2.coder()) {
        // compareToCI : Case를 무시하고 compare하는 것을 의미
            return s1.isLatin1() ? StringLatin1.compareToCI(v1, v2) : StringUTF16.compareToCI(v1, v2);
        }
        return s1.isLatin() ? StringLatin1.compareToCI_UTF16(v1, v2) : StringUTF16.compareToCI_Latin1(v1, v2);
    }
    private Object readResolve() { return CASE_INSENSITIVE_ORDER; }
}

String[] strArr = {"lion", "DOG", "TIGER", "cat"};
//아래와 같이 sort를 할때 CASE_INSENSITIVE_ORDER을 사용하게 되면
//CASE를 무시하게 되고 내림차순으로 정렬되게 된다.
Arrays.sort(strArr, String.CASE_INSENSITIVE_ORDER);
System.out.println("strArr = " + Arrays.toString(strArr)); 

하지만 위의 방식은 raw타입을 사용하기 때문에 예외가 생길 수 있다. 그래서 타입을 정해주는 다음과 같은 형식으로 코드를 짜줄 필요가 있다.

class Descending implements Comparator<String>{
    public int compare(String s1,String s2) {
        return s1.compareTo(s2)*2;
    }
}

public class Ex18_04 {
    public static void main(String[] args) {
        String[] strArr = { "lion", "DOG", "TIGER", "cat" };
        System.out.println("strArr = " + Arrays.toString(strArr));
        Arrays.sort(strArr);
        System.out.println("strArr = " + Arrays.toString(strArr));
        Arrays.sort(strArr, new Descending());
        System.out.println("strArr = " + Arrays.toString(strArr));
    }
}
728x90