7

I have an array of Musical Tracks and in this array the same song can show up multiple times due to being released on multiple albums. I am trying to remove them from the array so that only true uniques show up in the list.

The Hash looks something like this:

"tracks" => [
    [0] {
        "id" => 1,
        "Title" => "Intergalactic",
        "ArtistName" => "Beastie Boys"
    },
    [1] {
        "id" => 2,
        "Title" => "Intergalactic",
        "ArtistName" => "Beastie Boys"
    }
]

I am needing a way to remove the duplicates based on the Title key. Anyway of doing this?

0

3 Answers 3

11

If you are using ActiveSupport, you can use uniq_by, like so :

tracks.uniq_by {|track| track["title"]}

If not, then you can easily implement it yourself. See this.

# File activesupport/lib/active_support/core_ext/array/uniq_by.rb, line 6
  def uniq_by
    hash, array = {}, []
    each { |i| hash[yield(i)] ||= (array << i) }
    array
  end
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you so much for the help!!!! Each day that I am doing Ruby development I begin to become a happier/better person
10

The Array#uniq! method in 1.9 takes a block so if your Hash is h then:

h['tracks'].uniq! { |x| x['Title'] }

If you're in 1.8 then you can fake it with:

h['tracks'] = h['tracks'].group_by { |x| x['Title'] }.values.map(&:first)

I'm assuming that you want to modify it in-place.

4 Comments

Ah ! I didn't know it was in 1.9, thanks for the tip. Obviously if you are using 1.9 this is the right answer.
@DuoSRX: It doesn't seem to be that well known and it isn't exactly well documented (you have to infer it from the examples). A right answer is one that gets the job done :)
What if you need the entry to be unique by more than one value? I have the same situation, but need to check that Title, Artist and Composer be the same. With the uniq block I can only use one value!
@kakubei: What is %w[a b] == %w[a b]? I suspect that's the solution to your problem.
0

While the other methods are correct, I'll throw in a bit of extra sugar I found elsewhere on SO.

Using this extension of Symbol:

class Symbol
  def with(*args, &block)
    ->(caller, *rest) { caller.send(self, *rest, *args, &block) }
  end
end

Instead of writing simple iterative blocks like

foo_array.each{ |foo| foo.update_bar("baz") }, you can now use

foo_array.each &:update_bar.with("baz")

Similar to how you might write maybe_nil.try(:[], "key")...

foo_array.uniq{ |foo| foo["key"] } is now identical to

foo_array.uniq(&:[].with("key"))

I hope this helps

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.