stl 데이터 합치기

girneter의 이미지

class Some;
class Compare;

class SomeList {
private:
    set<Some, Compare> infolist;
public:
    ...
}

SomeList AAA;

위와 같이 STL set 을 member 로 갖는 class 가 있고
이 클래스 타입의 object AAA 가 있습니다

이제 매번
역시 SomeList 타입의 BBB 를 만들어
Some 데이터를 계속 추가하다가
모아놓은 그 데이터들을 AAA 에 쏟아붇고 (즉 추가하고)
BBB 는 해제하고,
다시 또 만들어서 추가하다가 AAA 에 쏟아부어서
AAA 에 계속 데이터가 쌓이게 됩니다.

이제 질문.
1. AAA 와 BBB 는 같은 클래스 타입이지만 infolist 는
private 으로 선언되어 있자나요.
BBB 에 있는 데이터들을 AAA 로 옮길때 어떻게 하는게
젤 바람직할까요?

쉽게 가자면 클래스에
set<>* getList() 함수를 만들어서
BBB 에서 set 꺼내고 이걸 AAA 의 set 에 추가해주면
되겠지만 private 데이터를 이렇게 밖으로 꺼내서
막 다뤄도 괜찮은건가요?

2. 제가 갖고 있는 STL 책에는
list 는 merge 함수를 제공하는데,
set 에는 없는것처럼 나와있습니다.
혹시 set 은 merge 함수가 없습니까?
그럼 두 set 을 합칠 때는 일반 알고리즘 merge 를 써야겠죠?
아니면 구조를 list 로 바꾸어서
매번 sort 시키고 merge 시키는게 더 나을까요?

doldori의 이미지

girneter wrote:
1. AAA 와 BBB 는 같은 클래스 타입이지만 infolist 는
private 으로 선언되어 있자나요.
BBB 에 있는 데이터들을 AAA 로 옮길때 어떻게 하는게
젤 바람직할까요?

그냥 insert를 하면 제일 쉽겠는데요.
class SomeList
{
public:
    void merge(SomeList& source)
    {
        infolist.insert(source.infolist.begin(), source.infolist.end());
        source.infolist.clear();
    }
};

SomeList aaa, bbb;
aaa.merge(bbb);

girneter wrote:
쉽게 가자면 클래스에
set<>* getList() 함수를 만들어서
BBB 에서 set 꺼내고 이걸 AAA 의 set 에 추가해주면
되겠지만 private 데이터를 이렇게 밖으로 꺼내서
막 다뤄도 괜찮은건가요?

상황에 따라 달라지지만 일반적으로는 좋지 않습니다. 이런 물음을 하신다는 것 자체가
문제가 있음을 느끼고 있다는 뜻이므로 이유는 길게 말씀드리지 않아도 되겠죠.

girneter wrote:
2. 제가 갖고 있는 STL 책에는
list 는 merge 함수를 제공하는데,
set 에는 없는것처럼 나와있습니다.
혹시 set 은 merge 함수가 없습니까?
그럼 두 set 을 합칠 때는 일반 알고리즘 merge 를 써야겠죠?

set에는 merge가 필요 없습니다. set::insert로 같은 일을 효율적으로 할 수
있으니까요. 일반적으로 정렬된 컨테이너를 합치기 위해서 merge나 set_union
알고리즘을 쓸 수 있지만 합친 결과를 담아둘 임시 컨테이너를 마련해야 하고 합친
후에 다시 원하는 컨테이너로 복사해야 합니다.
일반 알고리즘보다 컨테이너의 멤버 함수를 쓰는 것이 좋은 이유는 멤버 함수는
컨테이너 클래스의 내부 구조를 잘 알고 있으므로 같은 일을 해도 더 효율적으로
할 수 있기 때문입니다. (적어도 일반 알고리즘보다 비효율적이지는 않습니다.)

girneter wrote:
아니면 구조를 list 로 바꾸어서
매번 sort 시키고 merge 시키는게 더 나을까요?

번거롭지 않겠습니까? 성능의 저하도 예상되는군요.
girneter의 이미지

아...
set<>.insert(begin, end) 가 그렇게 쓰는거였구나

보고도 지나쳤습니다.
친절하고 명쾌한 답변 정말 고맙습니다.

내친김에 질문 하나 더 드릴께요.

object AAA 에서 BBB 의 private member 인
infolist 를 바로 접근할 수 있었던건
둘이 같은 클래스이기 때문이자나요

만약 다른 클래스인데 멤버로 같은 set<> 을 갖고
있는 경우였다면 어떻게 하나요?
할 수 없이 set<>* getList() 함수를 써야겠죠?
클래스 설계가 잘못되었으니 첨부터 다시 설계하든가.

혹은 friend 가 이럴때 사용하는거였던가?

개념없는 초딩들은 좋은 말로 할때 DC나 웃대가서 놀아라. 응?

doldori의 이미지

글쎄요... 두 클래스의 목적이라든가 서로간의 관계에 대한 정보가 없어서 대답하기
힘들군요. 정말 다양한 선택이 있을 수 있습니다.
딴 얘기지만 set을 합치는 것은 클래스의 구현에 관한 내용일 가능성이 높습니다.
구현 방법에 맞춰 인터페이스를 정하지 마시고 클래스가 충분히 추상화되었는지
거시적으로 생각해 보세요. Bjarne Stroustrup의 말을 인용합니다.

Quote:
I use as a rule of thumb that unless at least two significantly
different implementations of a class are possible, then there is probably
something wrong with the class. That is, it is simply an implementation
in disguise and not a representation of a proper concept.

The C++ Programming Language, 3rd ed

ssehoony의 이미지

set 에는 set<>.insert(begin, end) 이런 형식 없습니다.(두개의 iterator 파라미터)

집합의 더하기는 단순히 두 집합을 연결하는게 아니죠
(집합에 들어있는 원소는 유니크해야 하니깐요)
그래서 merge 를 사용 할 수 없습니다.
집합끼리는 합집합으로 하는거죠.
고로 set_union() 를 사용하세요. list merge 에 해당하는거죠

익명 사용자의 이미지

ssehoony wrote:
set 에는 set<>.insert(begin, end) 이런 형식 없습니다.(두개의 iterator 파라미터)

집합의 더하기는 단순히 두 집합을 연결하는게 아니죠
(집합에 들어있는 원소는 유니크해야 하니깐요)
그래서 merge 를 사용 할 수 없습니다.
집합끼리는 합집합으로 하는거죠.
고로 set_union() 를 사용하세요. list merge 에 해당하는거죠


set에 insert(begin,end) 가 없는 이유는,
"set에 들어갈 수 있는 key가 unique 해야 하기 때문에, insert하고자 하는 begin-end 사이에 이미 존재하는 키가 있을 경우에, 이를 추가할지 말지의 처리가 애매모호해서"
라고 보시는게 더 나을듯 합니다.
즉 정의될 수 없는 동작을 하려고 하기 때문이죠...

list에 있는 merge는 용도를 좀 알고 접근하셔야 할 듯 합니다.
merge라는 것이 두 list가 sort가 되어있다는 가정을 두고 있습니다.
listA.merge(listB)
이면 listC 는 listA와 listB가 하나로 합쳐지기는 하는것이지만,
listA와 listB가 sort되어 있다는 전제와 함께, 결과로 나오는 listA가 sort가 된 결과라는 전제가 깔리게 됩니다.
하지만, set은
1. 이러한 순차적인 데이터구조로만 정의되지는 않습니다.
(물론 std::set 의 begin -> end 가 순차적인 구조를 가지도록 유지할 수는 있기는 합니다만, 이는 std의 정의입니다.
set은 그냥 set으로 보시는게 맞을듯 합니다.)
2. 더구나, set에서 값들을 begin - end 를 보시면 아시겠지만 sort된 결과를 리턴하게 됩니다.
내부적으로 tree구조를 이용해서 (MFC의 set입니다. sgi 혹은 다른 std의 것은 어떻게 되어있는지는 모르겠습니다만..)
begin 부터 end 까지의 값들을 얻어내려 할 때에, 값들의 대소가 순서를 유지하도록 합니다.
물론, 이렇게 해야 값이 중복으로 들어가는 것을 피할 수 있겠지만요...
즉 set은 merge를 위한 선행조건과 목적을 만족할 수가 없고, 또한 만족 시킬 필요가 없기 때문에 존재하지 않는것입니다.

데이터를 순차적으로 가질 수 있고, 또한 순차적인 데이터를 sort할 수 있는 때, 순차적으로 sort된 두 데이터 집합의 merge의 결과는 두 집합을 합친 그리고 순차적인 데이터 구조를 유지하는 결과를 가진다.

htna의 이미지

헉 실수로 로그인을 안했군요.
윗글 제가 작성했습니다.

WOW Wow!!!
Computer Science is no more about computers than astronomy is about telescopes.
-- E. W. Dijkstra

doldori의 이미지

Anonymous wrote:
ssehoony wrote:
set 에는 set<>.insert(begin, end) 이런 형식 없습니다.(두개의 iterator 파라미터)

set에 insert(begin,end) 가 없는 이유는,
"set에 들어갈 수 있는 key가 unique 해야 하기 때문에, insert하고자 하는 begin-end 사이에 이미 존재하는 키가 있을 경우에, 이를 추가할지 말지의 처리가 애매모호해서"
라고 보시는게 더 나을듯 합니다.
즉 정의될 수 없는 동작을 하려고 하기 때문이죠...

input iterator 2개를 받는 set::insert도 있습니다.
template<typename Key, typename Compare, typename Allocator>
class set
{
public:
    template<typename InputIterator>
    void insert(InputIterator first, InputIterator last);
};

first와 last 범위를 순회하면서 이미 키가 존재한다면 추가하지 않고 넘어갑니다.
모호할 이유가 없지요.
hey의 이미지

set<>* getList() 대신 set<>::iterator& getBeginOfList()와 getEndOfList()를 만드는건 어떨까요?


----------------------------
May the F/OSS be with you..


ssehoony의 이미지

doldori wrote:
Anonymous wrote:
ssehoony wrote:
set 에는 set<>.insert(begin, end) 이런 형식 없습니다.(두개의 iterator 파라미터)

set에 insert(begin,end) 가 없는 이유는,
"set에 들어갈 수 있는 key가 unique 해야 하기 때문에, insert하고자 하는 begin-end 사이에 이미 존재하는 키가 있을 경우에, 이를 추가할지 말지의 처리가 애매모호해서"
라고 보시는게 더 나을듯 합니다.
즉 정의될 수 없는 동작을 하려고 하기 때문이죠...

input iterator 2개를 받는 set::insert도 있습니다.
template<typename Key, typename Compare, typename Allocator>
class set
{
public:
    template<typename InputIterator>
    void insert(InputIterator first, InputIterator last);
};

first와 last 범위를 순회하면서 이미 키가 존재한다면 추가하지 않고 넘어갑니다.
모호할 이유가 없지요.

네 두개의 iterator 을 받는 insert 가 set 에도 있었군요.
제가 원글을 쓸때 레퍼런스를 확인하고 쓴 글이었는데, 그때 발견하지 못했는데 지금 다시 확인해 보니 있네요.
잘 못된 내용 올려서 죄송합니다.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.