Ruby Array uniq() Method

Topics Covered

Overview

The Ruby uniq() method is a powerful tool in Ruby's Array class that allows developers to remove duplicate elements from an array. It is a convenient way to filter out repetitive values, resulting in a new array that contains unique elements. This method is particularly useful when dealing with large datasets or when you need to perform operations on unique elements within an array.

Syntax

The syntax for using the Ruby uniq() method is straightforward:

Here, array refers to the array object on which we want to invoke the Ruby uniq() method. By calling the Ruby uniq() method on an array, the method will return a new array with duplicate elements removed.

Parameters

The Ruby uniq() method does not accept any parameters. It operates solely on the array object it is called upon. This simplicity makes it easy to use, as you don't need to pass any additional arguments.

Return Value

  • The Ruby uniq() method returns a new array with unique elements from the original array.
  • The resulting array preserves the relative order of the elements based on their first occurrence in the original array.
  • The method does not modify the original array; it creates a new array with unique elements.
  • It efficiently removes duplicates by using a hash table to keep track of encountered elements.

Exception

The Ruby uniq() method does not raise any exceptions by default. However, if you attempt to call Ruby's uniq() method on a non-array object, Ruby will raise a NoMethodError. To avoid this error, ensure that you are calling the method on a valid array object.

How does the uniq() Method Work?

The uniq() method works by iterating over the elements in the array and comparing them to identify duplicates. Let us understand the working of this method by considering the following properties/attributes:

Stability

The uniq() method in Ruby's Array class preserves the order of elements based on their first occurrence in the array. This means that elements that appear later in the array, even if they are duplicates, are not included in the resulting array.

Consider the following example:

Output:

As you can see, the resulting array unique_array contains only the first occurrences of each element in the original array. The duplicates that appear later in the array, such as the second occurrence of 2 and the second occurrence of 1, are omitted from the result.

Element Comparison

The uniq() method compares elements using the eql? method, which by default behaves the same as the == operator. This means that elements are considered duplicates if they are equal according to the default equality comparison.

However, it's important to note that the behavior of element comparison can be overridden by providing custom equality logic for specific classes. By defining the eql? method or implementing the == operator differently for a class, you can control how elements are compared for uniqueness.

Modifying Blocks

When using the uniq() method with a block, the original array is not modified. The block is used only for determining uniqueness during the method execution.

Let's consider an example to demonstrate this behavior:

Output:

In this example, the block { |element| element % 2 } is provided to the uniq() method. The block is executed for each element in the array, and the return value of the block is used to determine uniqueness. In this case, the block returns 1 for odd elements and 0 for even elements. As a result, the uniq() method keeps only one occurrence of odd elements and one occurrence of even elements in the resulting array.

It's important to note that the original array remains unchanged.

Time Complexity:

The time complexity of the uniq() method is O(n), where n is the number of elements in the array. This makes it an efficient choice for removing duplicates, even with large arrays.

How to Use Ruby uniq() Method With a Block?

In addition to the basic usage of the uniq() method, Ruby allows us to provide a block of code that defines custom logic for determining uniqueness. This feature is particularly useful when we need to perform more complex comparisons between elements.

To use uniq() with a block, we modify the syntax as follows:

In this form, the block receives each element from the array, and we can define our custom logic within the block. The block should return a value that represents the uniqueness of the element. If multiple elements return the same value, only the first occurrence will be included in the resulting array.

Let's consider some examples to illustrate the usage of uniq() with a block.

Example - 1: Filtering Fruits Based on Their Name Length

Suppose we have an array of strings representing fruits, and we want to remove duplicates based on the length of the fruit names:

Output:

In this case, the block {|fruit| fruit.length} returns the length of each fruit name. The uniq() method uses this information to remove fruits with duplicate lengths. The resulting unique_fruits array will contain only one fruit per distinct length.

Example - 2: Filtering Unique Numbers by Evenness

Output:

Here's how the code works:

  • numbers.uniq removes duplicates, resulting in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].
  • select { |num| num.even? } filters even numbers.
  • unique_even_numbers contains unique even numbers from the original array.

Example - 3: Removing Duplicate Words by Last Character

Output:

In this example, we use a block with uniq() to define uniqueness based on the last character of each word. The block {|word| word[-1]} extracts the last character of each word, and the resulting array contains only words with distinct last characters.

How to Use uniq() With Multiple Conditions?

In some scenarios, we may need to apply multiple conditions to determine uniqueness. For example, consider an array of hashes representing people, where each hash contains name and age. We want to remove duplicates based on both name and age.

To achieve this, we can combine the properties in a way that uniquely identifies each element using a block with multiple variables.

Example - 1: Removing Duplicate Objects with Multiple Properties

Output:

In this example, the block {|person| [person[:name], person[:age]]} returns an array containing the name and age of each person. By combining both properties, we can identify duplicates and remove them from the resulting array.

Example - 2: Filtering Unique Students by Name and Grade

Output:

In this example, we have an array of students consisting of Student objects with name and grade properties. We override the == method in the Student class to compare both name and grade. By calling uniq() on the array of students with a block, we can ensure that duplicates are identified based on both properties. The resulting unique_students array will contain only the unique Student objects.

More Examples

Let's explore some more examples to see the uniq() method in action:

Example - 1: Removing Duplicate Numbers

Output:

In this example, we have an array of numbers with duplicate numbers. By calling uniq() on numbers, we obtain a new array unique_numbers that contains only the unique elements.

Example - 2: Removing Duplicate Strings

Output:

In this example, we have an array of fruits with duplicate strings representing different fruits. By calling uniq() on fruits, we obtain a new array unique_fruits that contains only the unique fruit names.

Example - 3: Custom Uniqueness Based on First Character

Output:

In this example, we use a block with uniq() to define uniqueness based on the first character of each word. The resulting unique_words array contains only words that have a distinct first character.

Example - 4: Nested Arrays

It's important to note that the uniq() method operates only on the top-level elements of an array. If the array contains nested arrays, the method will not recursively remove duplicates from the nested arrays.

Consider the following example:

Output:

In this case, the uniq() method treats the nested arrays as separate elements. Even though the elements of the array [3, 3, 4] contain duplicates inside them, they are not removed because they are unique and are checked only at the outer level. If you want to remove duplicates from nested arrays, you would need to apply the uniq() method to each nested array individually.

Example - 5: Empty Arrays

Calling the uniq() method on an empty array will also return an empty array. Since an empty array has no duplicate elements to remove, the result will be an empty array as well.

For example:

Output:

In this case, the uniq() method does not modify the empty array since there are no elements to process.

Example - 6: Chaining Methods

The uniq() method can be easily combined with other array methods by chaining them together. This allows for concise and expressive code that performs multiple operations on an array.

Consider the following example:

Output:

In this example, the select() method is used to filter elements greater than 3, and the resulting array is then passed to the uniq() method to remove duplicates. By chaining these methods together, you can perform multiple operations on an array in a single line of code, enhancing readability and maintainability.

Conclusion

  • uniq() in Ruby's Array class removes duplicates efficiently.
  • Great for large datasets or unique element operations.
  • Syntax: array.uniq
  • Returns a new array with unique elements in the original order.
  • Raises NoMethodError on non-array objects.
  • Custom logic can be used for complex comparisons.