프로그래밍/java

[JAVA] Comparator

승민아 2022. 6. 5. 23:57

개인적으로 작성한 클래스들을 이용하기에 개인적으로 개념정리하는 글입니다.

 

개인적으로 작성한 Score 클래스를 정렬을 구현하기 위해 implements Comparable<Score>를 추가해주자.

class Score implements InterScore, Comparable<Score>
{
	...
	private String No;
	private int sc[];	
    ...
    public int compareTo(Score other) // 정렬 기준 메소드 구현
    {
		Double myAvg = getAvg(); // sc에 담긴 int의 평균을 반환
        Double otherAvg = getAvg(); // 평균 반환
        return myAvg.compareTo(otherAvg); // Wrapper 클래스는 이미 적절한 compareTo()를 가지기에
        									// 그것을 사용해 반환했음.
	}
}

인터페이스 Comparable에 있는 compareTo를 구현했다.

Wrapper 클래스는 이미 적절한 compareTo()가 있기에 평균 비교를 반환할때 사용했다.

 

 

아래는 각 기능을 수행하는 함수인데 7일때 아래의 함수를 switch문을 실행한다.

class ApplyMng{

	void mng()
    {
    		...
            case 7: Arrays.sort(apply,Comparator.nullsLast(Comparator.reverseOrder()));
		    		System.out.println(this);
		    		break;
            ...
     }               
}

 

배열일때 Arrays.sort로 정렬을 한다.

( Score apply[]; )

 

 

Arrays.sort(apply,Comparator.nullsLast(Comparator.reverseOrder())); 를 자세히 보겠다.

일단 Collection이 아니라 Arrays에 있는 sort를 사용한다.

그런데 이 Arrays의 sort는 배열에 null이 있을경우 에러가 발생한다.(정렬한 apply에는 실제로 null이 존재하기에 주의하기)

그래서 아래의 함수를 이용해 null을 맨 뒤로 보내고 null이 존재하는곳 앞까지만 정렬을 진행하는것이다.

Comparator.nullsLast()

 

그런데 기본적으로 정렬은 오름차순이라

나는 내림차순을 원하기에 아래의 함수를 사용한다.

Comparator.reverseOrder()

 

그래서 null은 맨뒤로 보내고 null이 존재하는곳 앞까지만 정렬하는데 내림차순으로 정렬을 원하기에 아래처럼 사용한 것.

Arrays.sort(apply,Comparator.nullsLast(Comparator.reverseOrder()));

nullsLast()안에 reverseOrder()를 넣어준 형태다.

 

다른 정렬 기준을 추가할 때 Comparator 구현클래스 추가

 

먼저 Comparator 구현한 클래스를 작성

class NoComp implements Comparator
{
	private static NoComp nc = new NoComp(); //하나의 객체만 만듦
    private NoComp() { } // 외부에서 생성자를 못 부르게함.
    public static NoComp getInstance() { return nc; }
    
    public int compare(Object o1, Object o2)
    {
    	Score s1 = (Score)o1;
        Score s2 = (Score)o2;
        String n1 = s1.getNo();
        String n2 = s2.getNo();
        return n1.compareTo(n2); // String의 compareTo를 사용했기에 오름차순 정렬임.
    }

 

case 7 : 
	Arrays.sort(apply, Comparator.nullsLast(Comparator.naturalOrder());
    System.out.println("평균 오름차순\n"+this);
    
    Arrays.sort(apply, Comparator.nullsLast(Comparator.reverseOrder());
    System.out.println("평균 내림차순\n"+this);
    
    NoComp nc = NoComp.getInstance();
    Arrays.sort(apply, Comparator.nullsLast( nc ));
    System.out.println("응시번호 오름차순\n"+this);
    
    Arrays.sort(apply, Comparator.nullsLast( nc.reversed() ));
    System.out.pruntln("응시번호 내림차순\n"+this);

 

사실 위의 코드는 아래 코드의 개선안이다.

위의 코드는 매번 새 객체를 생성할 필요 없이 하나의 객체 nc를 공유하지만

아래의 코드는 새로운 객체를 생성해야 한다..

class NoComp implements Comparator
{
	public int compare(Object o1, Object o2)
    {
    	Score s1 = (Score)o1;
        Score s2 = (Score)o2;
        String n1 = s1.getNo();
        String n2 = s2.getNo();
        return n1.compareTo(n2);
    }
}

-----> NoComp nc = new NoComp();
		Arrays.sort(apply, Comparator.nullsLast( nc ));
        
        또는
        Arrays.sort(apply, Comparator.nullsLast(new NumComp()));

매번 생성해야 하는 nc를 NoComp.getInstance()로 개선한 것이다.

 

정리하자면,

클래스의 정렬 기준이 하나일 때 compareTo() 메소드를 추가

class AAA implements Comparable<AAA>
{
	public int compareTo(AAA other)
    {
    	기준 비교 코드
        return 정수; // 0: 같다, 음수: 적다, 양수: 크다
    }
}

배열 다루는 클래스에서 정렬할 땐 compareTo를 구현하고

Arrays.sort(aaa);

 

정렬 기준이 여러 개일 때 Comparator 클래스를 추가 구현한다.

class 기준A implements Comparator
{
	private static NoComp nc = new NoComp();
    private NoComp() { }
    public static NoComp getInstance() { return nc; }
    public int compare(Object o1, Object o2)
    { 기준 비교 코드; return 정수; }
}

배열 다루는 클래스의 mtd에서

기준A ob = 기준A.getInstance();
Arrays.sort(apply, ob);

 

간단히

class NumComp implements Comparator 
{
	public int compare(Object o1, Object o2)
	{
		Score s1 = (Score)o1;
		Score s2 = (Score)o2;
		return s1.getNo().compareTo(s2.getNo());
	}
	
}
 NumComp nc = new NumComp();
Collections.sort(apply, nc);
System.out.println(this);

Vector 정렬


Vector<Score> apply; 이렇게 존재

class Score implements InterScore, Comparable<Score>
{
	...
    public int compareTo(Score other)
    {
    	Double my = getAvg();
        Double your = other.getAvg();
        return my.comepareTo(your);
	}
}

class NoComp implements Comparator
{
	public int compare(Object o1, Object o2)
	{
		Score s1 = (Score)o1;
		Score s2 = (Score)o2;
		return s1.getNo().compareTo(s2.getNo()); // String인 No의 compareTo는 오름차순
	}
}

 

사용

case 7:
	Collections.sort(apply,Collections.reverseOrder());
    System.out.println("평균 내림차순\n"+this);
    // 	Collections.sort(apply); 기본은 오름차순인데 reverseOrder을 했기에 내림이된것임. 
    
    NoComp nc = NoComp.getInstance(); //NoComp nc = new NoComp();
    Collections.sort(apply,nc);
    System.out.println("응시번호 오름차순\n"+this);

 

HashMap Key 정렬

HashMap<String,Score> apply;

 

// key 정렬 & 출력 방법1
Set<String> keys = apply.keySet();
Object karr[] = keys.toArray();
Arrays.sort(karr);
System.out.println("Key 오름차순 정렬1\n"+karr); // karr의 toString을 안만들어줘서 이상하게나옴
for(Object k : karr)
	System.out.println( apply.get(k) ); // toString이 정의되어 있어 잘 나옴
//=====================================

String sarr[] = keys.toArray(new String[apply.size()]);
Arrays.sort(sarr, Comparator.reverseOrder());
System.out.println("key 내림차순 정렬2\n"+sarr);
for(String k : sarr)
	System.out.println( apply.get(K) );

 

위의 방법 1, 2의 차이는 아래와 같다.

Set<String> keys = apply.keySet();
Object karr[] = keys.toArray();   <====== Object 배열
//-------------
Set<String> keys = apply.keySet();
String sarr[] = key.toArray( new String[apply.size()]);  <======= <K> 배열

 

HashMap values 정렬

( 형태 : HashMap<String,Score> apply; )

Collection<Score> vals = apply.values();
Score varr[] = vals.toArray( new Score[apply.size()] );
Arrays.sort(varr, Comparator.reverseOrder()); // 평균 내림차순 정렬

위에처럼 Score들을 정렬을 하기위해 

Score 클래스에 compareTo()로 정렬 기준을 아래처럼 구현해야 한다.

public int compareTo(Score oth)
{
		Double my = getAvg();
		Double your = oth.getAvg();
		return my.compareTo(your);		
}

위의 기준은 오름차순이지만 Comparator.reverseOrder()을 통해 평균 내림차순을 정렬된다.

정의한 정렬 기준으로 원하면 Comparator.naturalOrder()을 써주자.

 

또 다른 방법으로 ArrayList로 만들어 Collections를 통해 정렬하는 방법이 있다.

Collection<Score> values = apply.values();
ArrayList<Score> lstVal = new ArrayList<Score>(values);
Collections.sort(lstVal, Collections.reverseOrder() );

-> ArrayList<Score>() 생성자안에 values를 넣어주는것이다.

ArrayList 생성자에 Collection이 있기에 가능하다.