Array의 uniq에 block을 이용할 때, Array에 남는 객체에 일정한 규칙이 있습니까?

81 views
Skip to first unread message

Choongjae Lee

unread,
Jul 28, 2012, 10:16:44 AM7/28/12
to rub...@googlegroups.com
Array에 uniq 메소드를 종종 이용하게 되는데요
아시다시피 uniq에도 block을 줄 수 있습니다.

예를들어


[{a:1,b:2,name:"A"}, {a:2,b:1,name:"B"}, {a:1,b:1,name:"C"}].uniq {|t| t[:a]}.collect{|t| t[:name]}
 => ["A", "B"] 

와 같은 결과를 얻을 수 있는데요

자세히 보시면 A와 C가 같은 a:1값을 가지고 있어서 C가 사라진 것을 알 수 있습니다.

하지만 block으로 판단하여 A와 C가 같지만, 사실은 b의 값이 각각 1, 2로 다릅니다.
이 때 C가 아니라 왜 A가 남는것인지, 이렇게 남는 객체에 일정한 규칙이 있나요? (예를들어, 순서상으로 앞서는게 무조건 남는다거나..)

아시는 분들 도움 부탁드립니다 ㅎ 감사합니다

paranoiase

unread,
Jul 29, 2012, 12:31:51 AM7/29/12
to rub...@googlegroups.com

제가 지금 컴퓨터가 없어서 실험해보진 못하겠는데, uniq에서 블럭으로 a만 비교하고 계신 것 아닌가요? (uniq {|t| t[:a]})
a와 b를 같이 비교해주시면 잘 동작할 것 같습니다.

cogniti

unread,
Jul 29, 2012, 2:46:37 AM7/29/12
to rub...@googlegroups.com
함수 설명이 자세히 안 나와서 정확한 답변은 아니지만
C언어에 비교하자면 중지 연산(short circuit)으로 바라보는 것이 나을 듯 하네요.

그리고 uniq 값(기본키 primary key)이라는 게...
a=>1, a=>2 이렇게 a가 값을 2개 동시에 지시할 수는 없거든요.

그러면 기본키로 a,b를 사용한다면
a=>1, b=>1, c=>"a"
a=>1, b=>1, c=>"b"
이런 식으로 기본키 a,b가 값을 "a", "b" 이렇게 두 개를 지시해서도 안 되겠죠.


아무튼 uniq 함수를 사용하는 의미가 퇴색되지만 원하는 값을 얻으려면 이렇게 해야 할 것 같네요.

a, b 동시 비교

[{a:1,b:2,name:"A"}, {a:2,b:1,name:"B"}, {a:1,b:1,name:"C"}].uniq {|t|

[t[:a], t[:b]]}

a, b,c 동시 비교

[{a:1,b:2,name:"A"}, {a:2,b:1,name:"B"}, {a:1,b:1,name:"C"}].uniq {|t| t}
[{a:1,b:2,name:"A"}, {a:2,b:1,name:"B"}, {a:1,b:1,name:"C"}].uniq {|t|

[t[:a], t[:b], t[:c]]}

2012년 7월 29일 오후 1:31, paranoiase <paran...@gmail.com>님의 말:

Choongjae Lee

unread,
Jul 29, 2012, 7:41:33 PM7/29/12
to rub...@googlegroups.com
질문을 조금 잘못이해하신 것 같은데요,

A가 아니라 C가 남게 하는 방법 같은건 없는가가 제 궁금한 부분입니다 ㅎ
예를들면 a가 같을 때 b의 값이 큰 객체를 남긴다거나 하는 것입니다(이건 복잡할 것 같고)

그래서 남는 객체에 일정한 규칙이 있다면 (순서상으로 앞에있는 객체가 무조건 남는다거나)
미리 sort를 하고 uniq를 하거나 하는식으로 할 수 있을 것 같아서요.

사실 제가 직접 map reduce같은 식으로 코드를 만들어도 되는데
기존에 있는 메소드를 쓰면 프로그래밍할 때 스트레스가 줄 것 같아서
남는 객체의 규칙이나 좀 더 복잡하게 block을 쓴다거나 하는 방법을 아시는 분이 계시는가 싶어 질문을 했습니다


2012년 7월 29일 일요일 오후 1시 31분 51초 UTC+9, paranoiase 님의 말:

Sung-Min Park

unread,
Jul 29, 2012, 9:07:29 PM7/29/12
to rub...@googlegroups.com

Junegunn Choi

unread,
Jul 30, 2012, 12:02:37 PM7/30/12
to rub...@googlegroups.com
문서 상에 그러한 경우의 동작에 대한 정의가 안 되어 있기 때문에
특정 Ruby 구현 방식에 의존하시기 보다는 명확하게 기술하시는 편이 나을 듯 합니다.

이런 경우는 group_by 를 쓰면 편하겠네요.

[{a:1,b:2,name:"A"}, {a:2,b:1,name:"B"}, {a:1,b:1,name:"C"}].group_by
{ |e| e[:a] }.map { |_, v| v.sort_by { |e| e[:b] }.first[:name] }

--
cheers,
junegunn choi.

Sung Min Park

unread,
Jul 30, 2012, 4:51:08 PM7/30/12
to rub...@googlegroups.com
이경우 굳이 이렇게 알려 드리는것 보다 삽질한번 해보시는게 도움 될것 같아서 넘겼는데… 

원칙적으로 스펙에 명시되지 않은 기능에 의존하시면 않됩니다. 내부 구현은 언제든 바뀔 가능성이 있습니다.
심지어 플랫폼 별로 다른 결과가 나올 가능성도 있습니다.

이렇게 만들어지는 버그는 나중에 찾을수가 없습니다. ㅠ_ㅠ 

Choongjae Lee

unread,
Jul 31, 2012, 8:44:02 AM7/31/12
to rub...@googlegroups.com
좋은 예 감사합니다

2012년 7월 31일 화요일 오전 1시 2분 37초 UTC+9, junegunn choi 님의 말:

Choongjae Lee

unread,
Jul 31, 2012, 8:45:28 AM7/31/12
to rub...@googlegroups.com
아 ㅋㅋ 문서에 소스가 나와있는걸 알고는 있는데 제대로 읽어볼 생각을 안했었네요 ㅋㅋ
좋은 지적 감사합니다 ㅎㅎ
그리고 스펙에 없는건 버그의 지름길이라는건 명심하겠습니다 ㅎ 감사합니다

2012년 7월 30일 월요일 오전 10시 7분 29초 UTC+9, Sung-Min Park 님의 말:
Reply all
Reply to author
Forward
0 new messages