Lv 0. 특이한 정렬. pair에 대한 first와 second 원소에 대한 개별 sort 적용시키기 위한 커스텀 comp 함수를 이용한 sort. *다시 풀어보기*

https://school.programmers.co.kr/learn/courses/30/lessons/120880

 

#include <string>
#include <vector>
#include <algorithm>

using namespace std;

bool comp(pair<int,int> a, pair<int,int> b){
    if(a.first==b.first) return a.second>b.second;
    else return a.first<b.first;
}

vector<int> solution(vector<int> numlist, int n) {
    vector<int> answer;
    vector<pair<int,int>> a;
    int len=numlist.size();
    for(int i=0; i<len; i++){
        a.push_back({abs(n-numlist[i]),numlist[i]});
    }
    sort(a.begin(),a.end(),comp);
    for(auto c: a){
        answer.emplace_back(c.second);
    }
    return answer;
}

sort()를 적용할때, comp() 새로 정의해서 sort()에 세번째 인자로 전달해서 원하는 형태로 sort를 진행시키기 위해서, 어떤식으로 comp 함수를 작성해야 할지에 대해서 많은 시행착오를 거쳐서 겨우 완성시켜서, 하나의 comp 함수의 전달을 통해서 first와 second가 다른 우선순위를 통한 정렬을 하도록 만들어서 통과할 수 있었다. 이때에 거의 10개에 가까운 comp 함수들을 만들면서 시도해보았는데, 

위의 함수를 만든건 거의 우연에 가까운 일이었다. 

if((a.first<b.first)&&(a.second>b.second)) return a<b; 형태로 처음에 작성해서 comp 함수를 전달했는데, 위와 같은 함수의 경우는 제대로 동작하지 않고 second에 대한 내림차순으로만 결과가 나와서 위와 같은 형태에서 생각이 벗어나지 못해서 답을 찾는데 굉장히 오래걸렸다. 

위에 내가 작성한 comp 함수도, 결국에는 first에 대한 오름차순으로 우선적으로 정렬하고, 해당 정렬되어있는 vector에 대해서 다시 second에 대해서 같은 원소들의 first일 경우에 대해서 정렬해보자 라는 생각으로 작성했는데, 이것을 작성하고 나니까 

이렇게 작성하면 첫번째 first 에 대한 sort를 수행하지 않아도 이 함수 한번에 first와 second를 내가 원하는 형식으로 정렬할 수 있겠다는 생각이 들어서 제출해서 통과할 수 있었다. 

 

추가적으로, 이런 상황에서 필요한 comp 함수에 대해서 더 알아보기 위해 지피티를 통해 알아보았는데, 지피티의 답변을 통해서 int n을 comp 함수의 인자로 전달해서 사용하는 방법에 대해서 알아낼 수 있었다. 처음에는 제대로 된 방법을 제시해주지 않아서 추가적인 질문을 통해서, int n 을 사용하는 형태로 comp 함수를 선언하고, 해당 함수를 sort()의 세번째 인자로 전달할때, n을 어떤식으로 전달해주어야 하는지에 대해서 알아내었다. 

 

먼저 comp 함수를, 

bool customCompare(pair<int,int> a, pair<int,int> b, int n){
    if(a.second == b.second){
        return a.first> b.first;
    }
    return abs(a.first-n)<abs(b.first-n);
}

이와같이 n까지 인자로 전달받아야 하는 형태로 선언하고, 

 

sort() 함수에 대해서 comp 함수를 원소로 전달할때 아래와 같이 작성하면 n을 이용할 수 있는 형태로 sort() 함수에 comp 함수를 전달해줄 수 있다.  

   sort(a.begin(),a.end(),[n](pair<int,int> a, pair<int,int> b){
        return customCompare(a,b,n);
    });

위와 같은 두가지 요소들을 잘 고려해서 코드를 다시 작성해보면, 

 

#include <string>
#include <vector>
#include <algorithm>

using namespace std;

bool customCompare(pair<int,int> a, pair<int,int> b, int n){
    if(a.second == b.second){
        return a.first> b.first;
    }
    return abs(a.first-n)<abs(b.first-n);
}

vector<int> solution(vector<int> numlist, int n) {
    vector<int> answer;
    vector<pair<int,int>> a;
    int len=numlist.size();
    for(int i=0; i<len; i++){
        a.push_back({numlist[i],abs(n-numlist[i])});
    }
    sort(a.begin(),a.end(),[n](pair<int,int> a, pair<int,int> b){
        return customCompare(a,b,n);
    });
    for(auto c: a){
        answer.emplace_back(c.first);
    }
    return answer;
}

이렇게 작성한다면 n까지 고려한 comp 함수의 선언과, 해당 comp 함수를 sort()에 전달하는 형태로 프로그램을 작성할 수 있다. 

 

위의 경우 람다함수를 이용해서 sort() 함수에 전달해주는데, 이에 대해서 이해가 부족해서 지피티를 통해서 검색해보았다. 

`[n]`은 람다 함수(lambda function)의 캡처(capture) 부분을 나타냅니다. 람다 함수는 다른 함수 내에서 익명으로 정의되는 함수로, 주로 간단한 함수나 비교 함수 등을 정의할 때 사용됩니다. 이러한 람다 함수는 자신이 정의된 범위 내의 변수를 캡처할 수 있습니다.

여기서 `[n]`은 람다 함수가 외부 변수 `n`을 캡처하도록 지정한 부분입니다. 캡처란 람다 함수 내에서 외부 변수를 사용할 수 있도록 하는 메커니즘입니다. `[n]`은 `n` 변수를 캡처하라는 의미이며, 람다 함수 내에서 `n` 변수를 사용할 수 있게 합니다.

람다 함수의 일반적인 형태는 다음과 같습니다:

```cpp
[capture](parameter_list) -> return_type {
    // 함수 본문
}
```

- `capture`: 외부 변수를 캡처하는 부분입니다. `[n]`처럼 캡처하려는 변수나 값을 지정할 수 있습니다.
- `parameter_list`: 함수의 매개변수 목록입니다.
- `return_type`: 함수의 반환 타입을 지정합니다.
- 함수 본문: 람다 함수의 실제 동작을 정의하는 부분입니다.

람다 함수는 주로 함수나 알고리즘의 인자로 전달되거나, 람다 함수 내에서 간단한 작업을 수행할 때 사용됩니다. 위 코드에서는 `sort` 함수의 비교 함수로 람다 함수를 사용하여, `n` 변수를 캡처하여 `customCompare` 함수에 전달하는 역할을 합니다.

이와 같은 답변을 얻을 수 있었는데, 람다함수와 캡처에 대해서 아직 이해가 부족해서 위와 같은 설명을 첨부 해두고 다시 접하게 될때 다시 한번 더 공부해도록 하겠다. 

 

 

다른 사람의 풀이를 보니까, 내가 생각한 풀이들을 조금 더 간단하게 만드는 방법들이 존재하는 풀이들이 있어서 해당 풀이들을 첨부한다. 

우선적으로, 내가 pair를 사용하게 된 배경이 int n 이라는걸 그대로 사용할 수 없어서 변형된 형태로 넣다보니 pair를 사용한 것인데, 그 문제를 해결할 수 있는 방법으로 전역변수를 선언하고, 해당 변수에 n의 값을 넣은 형태로 작성하는 코드가 있어서 첨부해본다. 

#include <string>
#include <vector>
#include <algorithm>

using namespace std;

int num;

bool compare(int prev, int next) {
    if (abs(prev - num) == abs(next - num)) 
        return prev > next;
    return abs(prev - num) < abs(next - num);
}

vector<int> solution(vector<int> numlist, int n) {
    num = n;
    sort(numlist.begin(), numlist.end(), compare);
    return numlist;
}

위와 같이, 전역변수를 선언하고, solution 함수에서, 전역변수에 n 값을 대입하고, 그 solution 함수에서 compare 함수를 사용하면, 해당 compare 함수에서는 num을 이용하기 때문에 문제없이 n과 같은 값을 사용할 수 있는 형태로 작성할 수 있다. 

이처럼 전역변수를 선언하는 방법으로 해결할 수 있는게 첫번째 방법이고, 

 

두번째는 람다함수와 캡처를 활용하는 풀이인데, 훨씬 더 간결하게 작성해서 제출한 분이 있어서 해당 내용을 첨부해본다. 

#include <string>
#include <vector>
#include <algorithm>
using namespace std;

vector<int> solution(vector<int> numlist, int n) {

    sort(numlist.begin(),numlist.end(),[n](const auto& a,const auto& b)->bool{
       if(abs(n-a) == abs(n-b))
       {
           return a > b;
       }
       return abs(n-a) < abs(n-b);
    });
    return numlist;
}

이와 같이 작성하면 한번에 n을 사용하는 comp 함수를 sort 내부에서 람다함수를 사용해서 선언하고 해당 함수를 사용한 return 값을 그대로 sort()에 활용할 수 있는 형태로 되어있는 코드이다. 이렇게 작성해도 아주 좋을것 같다. 오히려 전역변수로 선언하고 해당 전역변수에 값을 대입하고, 해당 값을 compare 함수에서 사용하는 형태보다 이 형태가 훨씬 더 안정적인 형태의 프로그램 작성 방법이지 않을까 싶다. 

아직 람다함수를 사용하는것에 익숙하지 않지만, 이처럼 캡처를 이용한 형태로 람다함수를 작성하는걸 한번 시도해보도록 하자. 

 

 

++++++++++++++

`->`는 C++에서 람다 함수의 반환 타입을 지정하는 부분입니다. 람다 함수는 종종 반환 타입을 자동으로 추론할 수 있지만, 때로는 명시적으로 반환 타입을 지정해야 할 때가 있습니다. 이때 `->`을 사용하여 반환 타입을 지정할 수 있습니다.

람다 함수의 일반적인 형태는 다음과 같습니다:

```cpp
[capture](parameter_list) -> return_type {
    // 함수 본문
}
```

- `capture`: 외부 변수를 캡처하는 부분입니다.
- `parameter_list`: 함수의 매개변수 목록입니다.
- `-> return_type`: 함수의 반환 타입을 지정하는 부분입니다.
- 함수 본문: 람다 함수의 실제 동작을 정의하는 부분입니다.

`->` 오른쪽에 반환 타입을 명시하면, 컴파일러는 해당 타입으로 반환 값을 처리합니다. 반환 타입을 명시적으로 지정하지 않으면, 컴파일러는 람다 함수의 본문을 분석하여 반환 타입을 자동으로 추론하려고 시도합니다. 하지만 때로는 명시적으로 반환 타입을 지정하는 것이 코드의 가독성을 높일 수 있습니다.

위 코드에서는 `[n](const auto& a, const auto& b)->bool` 부분에서 람다 함수의 반환 타입을 명시적으로 `bool`로 지정하고 있습니다. 이것은 람다 함수가 `bool` 값을 반환한다는 것을 명시하는 역할을 합니다. 반환 타입을 명시하면 컴파일러는 반환 값이 해당 타입이 아니면 오류를 발생시킵니다.
  Comments,     Trackbacks