답변:
Array#uniq
블록과 함께 사용 :
@photos = @photos.uniq { |p| p.album_id }
require 'backports'
:-)
@photos.uniq &:album_id
uniq_by
프로젝트의 Array에 메서드를 추가합니다 . .NET과 유사하게 작동합니다 sort_by
. 그래서 uniq_by
이다 uniq
대로 sort_by
에있다 sort
. 용법:
uniq_array = my_array.uniq_by {|obj| obj.id}
구현 :
class Array
def uniq_by(&blk)
transforms = []
self.select do |el|
should_keep = !transforms.include?(t=blk[el])
transforms << t
should_keep
end
end
end
현재 배열을 수정하는 대신 새 배열을 반환합니다. 우리는 uniq_by!
방법을 작성하지 않았지만 원하신다면 충분히 쉬울 것입니다.
편집 : Tribalvibes는 그 구현이 O (n ^ 2)라고 지적합니다. 더 나은 것 같은 것입니다.
class Array
def uniq_by(&blk)
transforms = {}
select do |el|
t = blk[el]
should_keep = !transforms[t]
transforms[t] = true
should_keep
end
end
end
이 트릭을 사용하여 배열에서 여러 속성 요소별로 고유 한 항목을 선택할 수 있습니다.
@photos = @photos.uniq { |p| [p.album_id, p.author_id] }
귀하의 질문을 올바르게 이해했다면 Marshaled 객체를 비교하는 준 해킹 접근 방식을 사용하여이 문제를 해결하여 속성이 다른지 확인했습니다. 다음 코드 끝에있는 주입은 예입니다.
class Foo
attr_accessor :foo, :bar, :baz
def initialize(foo,bar,baz)
@foo = foo
@bar = bar
@baz = baz
end
end
objs = [Foo.new(1,2,3),Foo.new(1,2,3),Foo.new(2,3,4)]
# find objects that are uniq with respect to attributes
objs.inject([]) do |uniqs,obj|
if uniqs.all? { |e| Marshal.dump(e) != Marshal.dump(obj) }
uniqs << obj
end
uniqs
end
내가 찾은 가장 우아한 방법 Array#uniq
은 블록과 함께 사용하는 스핀 오프 입니다.
enumerable_collection.uniq(&:property)
… 그것은 또한 더 잘 읽습니다!
블록과 함께 Array # uniq 사용 :
objects.uniq {|obj| obj.attribute}
또는 더 간결한 접근 방식 :
objects.uniq(&:attribute)
Rails에는 #uniq_by
방법도 있습니다.
이제 속성 값을 정렬 할 수 있다면 다음을 수행 할 수 있습니다.
class A
attr_accessor :val
def initialize(v); self.val = v; end
end
objs = [1,2,6,3,7,7,8,2,8].map{|i| A.new(i)}
objs.sort_by{|a| a.val}.inject([]) do |uniqs, a|
uniqs << a if uniqs.empty? || a.val != uniqs.last.val
uniqs
end
이는 고유 한 1 속성에 대한 것이지만 사전 순 정렬로 동일한 작업을 수행 할 수 있습니다.