Repository: yegor256/cactoos
Pull request #1781 (2025-03-17 14:15:44)

Implement Set Intersection functionality
This PR adds a new `Intersection` class to the cactoos library that provides set intersection functionality. The implementation follows the same pattern as the existing `Diff` class.

## Features
- Implements set intersection operation (elements common to both sets)
- Provides multiple constructors to handle different input types:
  - Iterable
  - Iterator
  - Scalar
  - SetOf
- Includes comprehensive test coverage

## Implementation Details
The `Intersection` class extends `SetEnvelope<T>` and uses Java's `retainAll` method to compute the intersection between two sets. This approach is consistent with the existing `Diff` class implementation.

## Test Coverage
The test class includes tests for:
- Basic intersection functionality
- Intersection with empty sets
- Intersection with Java's built-in Set implementation
- Intersection with iterables and iterators

This implementation completes the set of basic set operations (union is already provided by SetOf, difference by Diff, and now intersection) making the library more comprehensive for set manipulation tasks.


Patch:
diff --git a/src/main/java/org/cactoos/set/Diff.java b/src/main/java/org/cactoos/set/Diff.java
index 800f93db..30349ca7 100644
--- a/src/main/java/org/cactoos/set/Diff.java
+++ b/src/main/java/org/cactoos/set/Diff.java
@@ -15,7 +15,7 @@ import org.cactoos.scalar.Unchecked;
  * <p>There is no thread-safety guarantee.</p>
  *
  * @param <T> Type of item
- * @since 0.49
+ * @since 0.58.0
  */
 public final class Diff<T> extends SetEnvelope<T> {
 
@@ -23,7 +23,6 @@ public final class Diff<T> extends SetEnvelope<T> {
      * Ctor.
      * @param first First set
      * @param second Second set
-     * @since 0.49
      */
     public Diff(final Iterable<T> first, final Iterable<T> second) {
         super(
@@ -38,7 +37,6 @@ public final class Diff<T> extends SetEnvelope<T> {
      * Ctor.
      * @param first First iterator
      * @param second Second iterator
-     * @since 0.49
      */
     public Diff(final Iterator<T> first, final Iterator<T> second) {
         this(
@@ -51,7 +49,6 @@ public final class Diff<T> extends SetEnvelope<T> {
      * Ctor.
      * @param first First iterable supplier
      * @param second Second iterable supplier
-     * @since 0.49
      */
     public Diff(
         final Scalar<Iterable<T>> first,
@@ -67,7 +64,6 @@ public final class Diff<T> extends SetEnvelope<T> {
      * Ctor.
      * @param first First set
      * @param second Second set
-     * @since 0.49
      */
     public Diff(final SetOf<T> first, final SetOf<T> second) {
         super(computeDiff(first, second));
@@ -79,7 +75,6 @@ public final class Diff<T> extends SetEnvelope<T> {
      * @param second The second set
      * @param <E> Type of elements
      * @return The difference set (elements in first but not in second)
-     * @since 0.49
      */
     private static <E> SetOf<E> computeDiff(
         final SetOf<E> first,
diff --git a/src/main/java/org/cactoos/set/Intersection.java b/src/main/java/org/cactoos/set/Intersection.java
new file mode 100644
index 00000000..f0d02bcc
--- /dev/null
+++ b/src/main/java/org/cactoos/set/Intersection.java
@@ -0,0 +1,87 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2017-2025 Yegor Bugayenko
+ * SPDX-License-Identifier: MIT
+ */
+package org.cactoos.set;
+
+import java.util.Iterator;
+import org.cactoos.Scalar;
+import org.cactoos.iterable.IterableOf;
+import org.cactoos.scalar.Unchecked;
+
+/**
+ * Set intersection.
+ *
+ * <p>There is no thread-safety guarantee.</p>
+ *
+ * @param <T> Type of item
+ * @since 0.58.0
+ */
+public final class Intersection<T> extends SetEnvelope<T> {
+
+    /**
+     * Ctor.
+     * @param first First set
+     * @param second Second set
+     */
+    public Intersection(final Iterable<T> first, final Iterable<T> second) {
+        super(
+            computeIntersection(
+                new SetOf<>(first),
+                new SetOf<>(second)
+            )
+        );
+    }
+
+    /**
+     * Ctor.
+     * @param first First iterator
+     * @param second Second iterator
+     */
+    public Intersection(final Iterator<T> first, final Iterator<T> second) {
+        this(
+            new IterableOf<>(first),
+            new IterableOf<>(second)
+        );
+    }
+
+    /**
+     * Ctor.
+     * @param first First iterable supplier
+     * @param second Second iterable supplier
+     */
+    public Intersection(
+        final Scalar<Iterable<T>> first,
+        final Scalar<Iterable<T>> second
+    ) {
+        this(
+            new Unchecked<>(first).value(),
+            new Unchecked<>(second).value()
+        );
+    }
+
+    /**
+     * Ctor.
+     * @param first First set
+     * @param second Second set
+     */
+    public Intersection(final SetOf<T> first, final SetOf<T> second) {
+        super(computeIntersection(first, second));
+    }
+
+    /**
+     * Compute the intersection between two sets.
+     * @param first The first set
+     * @param second The second set
+     * @param <E> Type of elements
+     * @return The intersection set (elements in both first and second)
+     */
+    private static <E> SetOf<E> computeIntersection(
+        final SetOf<E> first,
+        final SetOf<E> second
+    ) {
+        final SetOf<E> result = new SetOf<>(first);
+        result.retainAll(second);
+        return result;
+    }
+}


Test patch:
diff --git a/src/test/java/org/cactoos/set/DiffTest.java b/src/test/java/org/cactoos/set/DiffTest.java
index d0508ce0..e83b2b07 100644
--- a/src/test/java/org/cactoos/set/DiffTest.java
+++ b/src/test/java/org/cactoos/set/DiffTest.java
@@ -15,13 +15,12 @@ import org.llorllale.cactoos.matchers.HasValues;
 /**
  * Test case for {@link Diff}.
  *
- * @since 0.49
+ * @since 0.58.0
  */
 final class DiffTest {
 
     /**
      * Tests that set difference can be computed correctly.
-     * @since 0.49
      */
     @Test
     void computesSetDifference() {
@@ -37,7 +36,6 @@ final class DiffTest {
 
     /**
      * Tests that set difference with empty second set returns the first set.
-     * @since 0.49
      */
     @Test
     void computesSetDifferenceWithEmptySecondSet() {
@@ -53,7 +51,6 @@ final class DiffTest {
 
     /**
      * Tests that set difference with empty first set returns empty set.
-     * @since 0.49
      */
     @Test
     void computesSetDifferenceWithEmptyFirstSet() {
@@ -69,7 +66,6 @@ final class DiffTest {
 
     /**
      * Tests that set difference works with java.util.Set.
-     * @since 0.49
      */
     @Test
     void computesSetDifferenceWithJavaUtilSets() {
@@ -90,7 +86,6 @@ final class DiffTest {
 
     /**
      * Tests that set difference works with iterables.
-     * @since 0.49
      */
     @Test
     void computesSetDifferenceWithIterables() {
@@ -106,7 +101,6 @@ final class DiffTest {
 
     /**
      * Tests that set difference works with iterators.
-     * @since 0.49
      */
     @Test
     void computesSetDifferenceWithIterators() {
diff --git a/src/test/java/org/cactoos/set/IntersectionTest.java b/src/test/java/org/cactoos/set/IntersectionTest.java
new file mode 100644
index 00000000..784899a2
--- /dev/null
+++ b/src/test/java/org/cactoos/set/IntersectionTest.java
@@ -0,0 +1,116 @@
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2017-2025 Yegor Bugayenko
+ * SPDX-License-Identifier: MIT
+ */
+package org.cactoos.set;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import org.junit.jupiter.api.Test;
+import org.llorllale.cactoos.matchers.Assertion;
+import org.llorllale.cactoos.matchers.HasSize;
+import org.llorllale.cactoos.matchers.HasValues;
+
+/**
+ * Test case for {@link Intersection}.
+ *
+ * @since 0.58.0
+ */
+final class IntersectionTest {
+
+    /**
+     * Tests that set intersection can be computed correctly.
+     */
+    @Test
+    void computesSetIntersection() {
+        new Assertion<>(
+            "Can't compute the intersection of two sets",
+            new Intersection<>(
+                new SetOf<>(1, 2, 3),
+                new SetOf<>(2, 3, 4)
+            ),
+            new HasValues<>(2, 3)
+        ).affirm();
+    }
+
+    /**
+     * Tests that set intersection with empty second set returns empty set.
+     */
+    @Test
+    void computesSetIntersectionWithEmptySecondSet() {
+        new Assertion<>(
+            "Can't compute the intersection with empty second set",
+            new Intersection<>(
+                new SetOf<>(1, 2, 3),
+                new SetOf<>()
+            ),
+            new HasSize(0)
+        ).affirm();
+    }
+
+    /**
+     * Tests that set intersection with empty first set returns empty set.
+     */
+    @Test
+    void computesSetIntersectionWithEmptyFirstSet() {
+        new Assertion<>(
+            "Can't compute the intersection with empty first set",
+            new Intersection<>(
+                new SetOf<Integer>(),
+                new SetOf<>(1, 2, 3)
+            ),
+            new HasSize(0)
+        ).affirm();
+    }
+
+    /**
+     * Tests that set intersection works with java.util.Set.
+     */
+    @Test
+    void computesSetIntersectionWithJavaUtilSets() {
+        final Set<Integer> first = new HashSet<>();
+        first.add(1);
+        first.add(2);
+        first.add(3);
+        final Set<Integer> second = new HashSet<>();
+        second.add(3);
+        second.add(4);
+        second.add(5);
+        new Assertion<>(
+            "Can't compute the intersection of two java.util.Set",
+            new Intersection<>(first, second),
+            new HasValues<>(3)
+        ).affirm();
+    }
+
+    /**
+     * Tests that set intersection works with iterables.
+     */
+    @Test
+    void computesSetIntersectionWithIterables() {
+        new Assertion<>(
+            "Can't compute the intersection of two iterables",
+            new Intersection<>(
+                Collections.singletonList(1),
+                Collections.singletonList(1)
+            ),
+            new HasValues<>(1)
+        ).affirm();
+    }
+
+    /**
+     * Tests that set intersection works with iterators.
+     */
+    @Test
+    void computesSetIntersectionWithIterators() {
+        new Assertion<>(
+            "Can't compute the intersection of two iterators",
+            new Intersection<>(
+                new SetOf<>(1, 2, 3).iterator(),
+                new SetOf<>(3, 4, 5).iterator()
+            ),
+            new HasValues<>(3)
+        ).affirm();
+    }
+}