Enhancing Ruby Arrays with Custom Methods for Duplicates and Unique Elements

December 4, 2024

Introduction

Ruby arrays are a versatile and powerful data structure, but sometimes we need specific functionality to handle duplicates and extract unique elements. In this article, I’ll show you how to extend the Array class with two custom methods: has_duplicated? to check if an array contains duplicates, and unique_elements to return only the unique elements from the array. These methods make working with arrays more intuitive and flexible.


The Code

Let’s start with the code that extends the Array class with our two methods.

# lib/array.rb

class Array 
  # Method to check if the array contains duplicated elements
  def has_duplicated?
    # If the array's size is different from the unique elements, there are duplicates
    return false if self.size == self.uniq.size
    true
  end

  # Method to get unique elements (those that appear only once in the array)
  def unique_elements
    self.tally.select { |k, v| v == 1 }.map do |element|
      element.first
    end
  end
end
  • has_duplicated?: This method checks whether an array contains any duplicate elements. It compares the size of the array to the size of the array after calling uniq, which removes duplicates. If the sizes differ, it returns true, indicating the presence of duplicates.
  • unique_elements: This method leverages the tally method to count occurrences of each element in the array. It then selects elements that appear exactly once and returns them.

Do you need more hands for your Ruby on Rails project?

Fill out our form! >>

Do you need more hands for your Ruby on Rails project?

RSpec Tests

To ensure our methods work as expected, we can write some RSpec tests. Below is a test suite that checks both methods:

# spec/array_spec.rb

require "spec_helper"
require "array"
require "factories/students.rb"

RSpec.describe Array, "#arrays" do
  let(:students) { build_list(:student, 20) }

  before do
    @arr = (students + students).shuffle
    @last_names = @arr.map{ |stu| stu.last_name }
  end

  context "Return True if the array contains duplicated elements" do
    it "should return true because the array contains duplicated elements" do
      expect(@arr.has_duplicated?).to be_truthy
    end

    it "should return false because the array doesn't contain duplicated elements" do
      expect(students.has_duplicated?).to be_falsey
    end

    it "should return true because last names are duplicated" do
      expect(@last_names.has_duplicated?).to be_truthy
    end

    it "should return false because last names aren't duplicated" do
      @last_names = students.map{ |stu| stu.last_name }
      expect(@last_names.has_duplicated?).to be_falsey
    end
  end

  context "Return unique elements from the array" do
    it "Should return no elements when all elements are duplicated" do
      expect(@arr.unique_elements).to be_empty
    end

    it "should return all elements because they are unique" do
      expect(students.unique_elements).to match_array(students)
    end
  end
end
  • Test Setup: The students array is created using a factory, and we duplicate the array to test for duplicates. We also extract the last names to verify the methods against real data.
  • Test Cases:

has_duplicated? tests check whether duplicates are present in the array or not.

unique_elements tests verify that only elements that appear once are returned, or an empty array is returned if all elements are duplicated.


Factories for Test Data

In the tests, we use a Student factory to create test data. Here’s a basic factory definition for generating students with unique names and last names:

# spec/factories/students.rb

class Student
  attr_accessor :name, :last_name
end

FactoryBot.define do
  factory :student do
    name { Faker::Name.unique.name }
    last_name { Faker::Name.unique.last_name }
  end
end
  • FactoryBot: This gem helps generate test data, like students in our case. We use Faker to generate random names and last names for the students.

Usage Examples

Once you’ve added the methods to your project, you can use them like this:

# Example: Check if there are duplicated elements
array = [1, 2, 3, 2, 4, 5]
puts array.has_duplicated?  # Output: true

# Example: Get unique elements
array = [1, 2, 2, 3, 3, 4]
puts array.unique_elements  # Output: [1, 4]

Conclusion

In this article, we enhanced Ruby’s Array class with two custom methods: has_duplicated? and unique_elements. These methods provide useful functionality for dealing with duplicates and extracting unique elements from arrays, improving readability and reducing the need for repetitive code. I hope this guide helps you extend Ruby arrays to suit your needs!

Feel free to adapt these methods to your own projects and share any feedback or improvements you might have.

Leave a comment