2013-12-13 5 views
6

여러 가지 질문이 있지만 하나의 키만 사용한 적이 있습니다. 기간이 다른 또는 존재하지 않을 수도 있기 때문에 Ruby는 해시 배열에서 중복 항목을 제거하지만 둘 이상의 값을 기반으로합니다.

a = [{:name=>"Yes, Yes, Yes", :artist=>"Some Dude", :composer=> 'First Dude', :duration=>"3:21"}, 
{:name=>"Chick on the Side", :artist=>"Another Dude", :duration=>"3:20"}, 
{:name=>"Luv Is", :duration=>"3:13"}, 
{:name=>"Yes, Yes, Yes", :artist=>"Some Dude", :composer=> 'First Dude', :duration=>"2"}, 
{:name=>"Chick on the Side", :artist=>"Another Dude"}] 

a.uniq

여기에 작동하지 않습니다

나는 해시 다음과 같은 배열을 가지고있다. 데이터베이스에 동일한 이름, 아티스트 및 작곡가의 중복 항목을 허용하지 않는 고유 키를 설정 했으므로 사람들이이 3 가지 키에 중복 항목이있을 때가끔 오류가 발생합니다.

uniq 3 키를 확인하는 방법이 있습니까? 나는이 같은 블록 시도 :

new_tracks.uniq do |a_track| 
    a_track[:name] 
    a_track[:artist] 
    a_track[:composer] 
end 

을하지만 키가없는 곳은 아무 것도 무시합니다 (예를 들어, 위의 기준을 충족하지 않는 작곡가없이 항목).

나는 항상 :name 키를 사용할 수 있지만, 동일한 제목이지만 다른 아티스트 또는 작곡가의 편집에서 잠재적으로 유효한 트랙을 제거하고 있음을 의미합니다.

이것은 Ruby 2.0에 있습니다.

답변

13

uniq은 블록을 허용합니다. 블록이 주어지면 비교를 위해 블록의 반환 값을 사용합니다.

코드가 솔루션에 가까웠지만 코드에서 반환 값은 마지막으로 계산 된 문인 a_track[:composer]뿐입니다.

원하는 속성을 문자열에 결합하여 해당 문자열을 반환 할 수 있습니다.

new_tracks.uniq { |track| [track[:name], track[:artist], track[:composer]].join(":") } 

가능한 리팩토링

new_tracks.uniq { |track| track.attributes.slice('name', 'artist', 'composer').values.join(":") } 

또는이 (가) 조인을 수행 모델에서 사용자 지정 방법을 추가하고, 나는 당신의 질문을 이해하면

class Track < ActiveRecord::Base 
    def digest 
    attributes.slice('name', 'artist', 'composer').values.join(":") 
    end 
end 

new_tracks.uniq(&:digest) 
+0

위대한, ** 고마워요! ** 첫 번째 작품은 괜찮습니다 :'.uniq {| track | [트랙 [: 이름], 트랙 ​​[: 아티스트], 트랙 ​​[: 작곡가]. 조인 (":")}'. 두 번째 것은 나에게'SyntaxError : unexpected '}'오류를 주며 ']''을 기대합니다. 이 문제를 해결하면 정의되지 않은 메서드'attributes'가 생깁니다. 하지만 첫 번째 트릭을 않습니다. 다시 한번 감사드립니다. – kakubei

+0

구문 오류가 수정되었습니다. –

+0

그 줄에 여전히'정의되지 않은 메소드'attributes''가 있습니다 ... – kakubei

2

를 호출입니다, 그냥있어 uniq 블록 내의 올바른 데이터 조합 사용 문제 :

반환 (210)

:

[ 
    {:name=>"Yes, Yes, Yes", :artist=>"Some Dude", :composer=>"First Dude", :duration=>"3:21"}, 
    {:name=>"Chick on the Side", :artist=>"Another Dude", :duration=>"3:20"}, 
    {:name=>"Luv Is", :duration=>"3:13"} 
] 

uniq은 우리가 블록 내부에 아무것도 만들 수 있습니다, 그 비교를 위해 것을 사용합니다. 루비 배열을 비교하는 방법을 알고 있기 때문에 나는, 배열을 사용하는 것을 선택 해요,하지만 값은 MD5 체크섬 또는 CRC 체크 할 수 있다면 그 만든 의미 :

a.uniq{ |a_track| 
    OpenSSL::Digest::MD5.digest(a_track[:name] + (a_track[:artist] || '') + (a_track[:composer] || '')) 
} 
# => [{:name=>"Yes, Yes, Yes", :artist=>"Some Dude", :composer=>"First Dude", :duration=>"3:21"}, {:name=>"Chick on the Side", :artist=>"Another Dude", :duration=>"3:20"}, {:name=>"Luv Is", :duration=>"3:13"}] 

내가 (a_track[:artist] || '')를 사용해야 할 '우리가 할 수 있기 때문에 문자열에 nil을 연결하면 || ''은 빈 문자열을 대신 반환합니다.

+0

이것은 흥미 롭습니다. 저는이 접근법을 좋아합니다 :'a.uniq {| a_track | '시므온의 대답을 처음 보았습니다. 그래서 대답으로 받아 들였습니다. 그러나 나는이 것을 더 좋아합니다. 고마워. – kakubei

+0

또한 각 값을 'to_s'로 설정할 수 있습니다.이 값은 nils를 빈 문자열로 변환해야합니다. –

+0

우리는 할 수는 있지만 의도를 숨 깁니다. –

0

또 다른 방법은 values_at를 사용하는 것입니다.슬라이스와 조인을 사용하지 않으려는 경우

a.uniq {|hash| hash.values_at(:name, :composer, :artist)}