Concatenating items in the array

Tags:

프로그래밍에서 배열을 다루며 종종 발생하는 문제는 배열 내용을 출력하는 것입니다. 이때는 취향에 따라 다양하게 할 수 있겠습니다만 주로 다음과 같은 식이 될 것입니다.

{1, 2, 3, 4, 5}가 있을 때,
첫번째 유형은 1, 2, 3, 4, 5라고 출력하는 것이고
두번째 유형은
1
2
3
4
5
라고 출력하는 것이죠.

그런데 이런 사소한 아이디어도 실제 코드로 옮기려면 복잡해집니다. 왜냐하면 첫번째 유형은 자료 사이에 콤마를 두번째 유형은 자료 사이에 newline 을 넣어주어야 하기 때문입니다. 즉, 모든 원소마다 콤마를 찍거나 뉴라인을 해서는 안되고 처음~끝에서 두번째까지만 콤마 혹은 newline을 찍어야합니다.

그래서,

#include
#include
#include
#include

using namespace std;

int main()
{
int items[] = { 1, 2, 3, 4, 5 };
vector vi(items, items + 5);

ostringstream oss;
copy(vi.begin(), vi.end(), ostream_iterator(oss, ” “));

string result = oss.str();

cout << "[" << result << "]" << endl; cout << "[" << result.erase(result.size() - 1) << "]" << endl; return EXIT_SUCCESS; } [/code] 와 같이 코딩하고 실행하면, [code lang="cpp"] mkseo@mkseo:~/tmp$ ./a.out [1 2 3 4 5 ] [1 2 3 4 5] mkseo@mkseo:~/tmp$ [/code] 와 같이 결과가 나옵니다. 마지막 스페이스를 일부러빼야한다는거죠. 뭐 복잡한 테크닉이 있을 수 있겠지만 그 어느것도 elegant solution에 가깝지는 않습니다. 자바의 경우엔 '그냥 짠다..'라는 느낌이 더 강한 코드밖에 못짤거라 생각됩니다. C++로 더 삽을 뜰 수도 있겠지만, 그래봤자 결론은 '그래서 내가 C++이 싫은거라고, 쳇.' 정도 밖에 안되겠죠. (그러나 더 우아하게 짜실 수 있는 분은 커멘트 부탁합니다. 언제나 멋진코드는 환영!!) 루비가 놀라운 점은 바로 이런 것에 대한 해결책입니다. [code lang="ruby"] irb(main):003:0> print “[“, [1, 2, 3, 4, 5].join(” “), “]\n”
[1 2 3 4 5]
=> nil

다른 어떤 언어를 가져와도 루비처럼 리스트 초기화와 동시에 이처럼 한줄만으로 하나의 역할을 아름답게 처리하진 못할 것입니다. 더 흥미로운점은 \n은 *NIX에선 \n, 윈도우에선 \r\n으로 알아서 출력된다는 것이죠. 사소한 것이지만 결코 사소하지 않은 루비의 편리함/아름다움입니다.

p.s. C++ 코딩을 시작한 순간 루비가 머리를 떠나지를 않는군요ㅋ

Comments

8 responses to “Concatenating items in the array”

  1. 공성식 Avatar
    공성식

    좋은 정보에 대해 약간의 딴지를 거는 것 같아 죄송합니다만…

    1.

    요즘 랭귀지에서 문자열의 join과 split은 거의 기본입니다.
    대부분의 언어들이 이걸 지원하죠.

    1) 브라우저의 주소창에 다음과 같이 입력해 보세요.

    javascript: alert([1,2,3,4,5].join(‘, ‘));

    2) Python은 약간 특이하게도 이게 문자열의 메소드로 돼 있습니다.

    print “, “.join([“one”, “two”, “three”])

    3) VB나 .Net에도 있습니다.

    C++은 좀 오래된 언어이고 스탠다드의 제약을 많이 받는 언어라…
    Perl 이후에 나온 Serious한 언어라면 대부분 지원하는 것 같습니다.

    2.

    ##\n은 *NIX에선 \n, 윈도우에선 \r\n으로 알아서 출력된다는 것이죠.

    이게 올바른 표현인지 잘 모르겠습니다.
    특별히 OS별로 바꿔준다기 보다는 요즘엔 웬만한 어플리케이션들이 \r\n, \n, \r 이렇게 세 가지를 모두 줄바꿈으로 인식한다고 보는 편이 더 맞지 않을까 싶은데요…
    만약 이걸 루비가 임의로 바꾼다면 플랫폼 간에 호환성이 떨어질 것 같은데요…

    저도 join 메소드를 아주 유용하게 사용합니다.

  2. 홍민희 Avatar

    제가 생각하기에도 플랫폼에 따라 줄바꿈 앞에 캐리지 리턴을 추가하는 것이 제대로 된 정책인지 의문이 듭니다. 너무 간단하게 말씀하셔서 여러가지 경우가 있겠지만요.

    1. 문자열 객체 자체에서 치환
    2. 큰 따옴표 문자열 리터럴에 한해서 치환
    3. print 메서드 내에서의 치환
    4. 모든 입출력 스트림에서의 치환
    5. 콘솔 표준 입출력 스트림에 한해서 치환

    5번의 경우는 상관 없을 것 같습니다만, 4번 이하로는 파일 입출력에서 바이너리 데이터를 다룰 경우에 문제가 있을 듯합니다.

  3. 홍민희 Avatar

    그리고 문자열 결합은 요즘 언어들은 거의 다 지원하더군요.

    # Io (http://iolanguage.com/)
    writeln("[", list(1, 2, 3, 4, 5) join(" "), "]")
    
  4. MKSeo Avatar
    MKSeo

    음.. 텍스트인 경우 윈도우에서는 \n 이 \r\n 으로 바뀝니다. 이걸 어디서 봤는지 기억이 가물가물한데;; 일단 http://www.ruby-forum.com/topic/72548 에서도 이야기된 바 있구요.

    C++의 경우엔 일단은 없는 것으로 생각됩니다.
    http://groups.google.com/group/comp.lang.c++/browse_frm/thread/2cf6150aae7fc545

    자바의 경우엔 있습니다.
    http://rubyist.or.kr/blog/?p=243#comment-896

    답글 모두 감사드려요 ^^;

  5. JM Avatar

    뉴스그룹 링크에도 다양한 방법이 많네요. 저의 한 표:
    for(size_t i = 0; i < vi.size(); ++i) oss << (i?” “:””) << vi[i];

    하하, 이런 C프로그래머 스러운 -_-

  6. nohmad Avatar
    nohmad

    오히려 루비는 개행문자(“\n”)에 대해 거의 아무런 처리도 안해주는 반면, C/C++에서는 stdio 계열의 함수들에서 컴파일러가 자동으로 시스템에 맞게 변환해준다고 해야 할 것 같네요. Kernel#print나 IO#write의 경우 $\에 값을 지정해서 append를 할 수가 있긴 한데, 이건 플랫폼을 인식하는 것은 아닙니다. 루비는 유닉스의 컨벤션을 가능한한 다른 플랫폼에도 강요하려 하고 있고(File.join, File::Separator 같은 것조차 해당 시스템의 기본값이 아니죠), 이런 정책 때문에 Non-Unix 플랫폼에서 많은 비판이 있습니다.

  7. 이원구 Avatar

    C++을 주로 사용하는 개발자로써 언어에 대한 변명(?)을 해볼까 합니다.

    C나 C++은 위의 join과 같은 작업은 언어 차원에서 지원하지 않습니다. 왜냐하면 orthogonal하지 않기 때문이죠. 쉽게 다음과 같이 얘기할 수 있을 것 같습니다.

    “도대체 int array와 string이 무슨 관계가 있지?”

    즉, C++이 생각하기에는 int array를 string으로 만드는 것은 int array가 할 일이 아닌거죠. 따라서 이러한 작업은 사용자가 직접 해주어야 합니다. (물론 여기서 사용자란 라이브러리 제작자들도 포함되겠죠?)

    제가 C++로 작성해 본 join 함수는 아래입니다. iterator에 대해 decrement operator를 사용하기 위해 bidirectional iterator를 사용합니다.

    #include
    #include
    #include
    #include

    template
    std::string join(BidirectionalIterator first, BidirectionalIterator last, const std::string& sep = ” “)
    {
    using namespace boost::lambda;

    std::stringstream ss;
    std::for_each(first, –last, ss

  8. Re: Concatenating items in the array

    Concatenating items in the array 글에 대한 trackback입니다. 댓글에 <…> 괄호를 사용하니 이상해져서요. -_-;

    C++을 주로 사용하는 개발자로써 언어에 대한 변명(?)을 해볼까 합니다.

    C나 C++…

Leave a Reply

Your email address will not be published. Required fields are marked *