Repository: yegor256/cactoos
Pull request #1779 (2025-03-16 19:04:15)

Add Diff<T> class for computing set differences

## PR Description
```markdown
## Description
This PR introduces a new `Diff<T>` class that computes the set difference operation (A - B) between two sets. The class extends `SetEnvelope<T>` and provides multiple constructors to support different input types:

- Iterable<T>
- Iterator<T>
- Scalar<Iterable<T>>
- SetOf<T>

The implementation follows the Cactoos object-oriented approach and includes comprehensive test coverage.

## Implementation Details
- The `Diff` class computes elements that are in the first set but not in the second set
- Added multiple constructors to support various input types
- Implemented a private `computeDiff` method to handle the actual set difference operation
- Added thorough test cases covering various scenarios:
  - Basic set difference
  - Empty set handling (both first and second sets)
  - Working with java.util.Set
  - Working with Iterables and Iterators

## Test Coverage
The implementation includes tests for all edge cases and typical usage scenarios:
- Computing difference between two non-empty sets
- Computing difference with an empty second set
- Computing difference with an empty first set
- Working with java.util.Set instances
- Working with Iterables and Iterators

All tests pass successfully, demonstrating the correctness of the implementation.
```



Patch:
diff --git a/src/main/java/org/cactoos/set/Diff.java b/src/main/java/org/cactoos/set/Diff.java
new file mode 100644
index 00000000..800f93db
--- /dev/null
+++ b/src/main/java/org/cactoos/set/Diff.java
@@ -0,0 +1,92 @@
+/*
+ * 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 difference.
+ *
+ * <p>There is no thread-safety guarantee.</p>
+ *
+ * @param <T> Type of item
+ * @since 0.49
+ */
+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(
+            computeDiff(
+                new SetOf<>(first),
+                new SetOf<>(second)
+            )
+        );
+    }
+
+    /**
+     * Ctor.
+     * @param first First iterator
+     * @param second Second iterator
+     * @since 0.49
+     */
+    public Diff(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
+     * @since 0.49
+     */
+    public Diff(
+        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
+     * @since 0.49
+     */
+    public Diff(final SetOf<T> first, final SetOf<T> second) {
+        super(computeDiff(first, second));
+    }
+
+    /**
+     * Compute the difference between two sets.
+     * @param first The first set
+     * @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,
+        final SetOf<E> second
+    ) {
+        final SetOf<E> result = new SetOf<>(first);
+        result.removeAll(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
new file mode 100644
index 00000000..d0508ce0
--- /dev/null
+++ b/src/test/java/org/cactoos/set/DiffTest.java
@@ -0,0 +1,122 @@
+/*
+ * 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 Diff}.
+ *
+ * @since 0.49
+ */
+final class DiffTest {
+
+    /**
+     * Tests that set difference can be computed correctly.
+     * @since 0.49
+     */
+    @Test
+    void computesSetDifference() {
+        new Assertion<>(
+            "Can't compute the difference of two sets",
+            new Diff<>(
+                new SetOf<>(1, 2, 3),
+                new SetOf<>(2, 3, 4)
+            ),
+            new HasValues<>(1)
+        ).affirm();
+    }
+
+    /**
+     * Tests that set difference with empty second set returns the first set.
+     * @since 0.49
+     */
+    @Test
+    void computesSetDifferenceWithEmptySecondSet() {
+        new Assertion<>(
+            "Can't compute the difference with empty second set",
+            new Diff<>(
+                new SetOf<>(1, 2, 3),
+                new SetOf<>()
+            ),
+            new HasValues<>(1, 2, 3)
+        ).affirm();
+    }
+
+    /**
+     * Tests that set difference with empty first set returns empty set.
+     * @since 0.49
+     */
+    @Test
+    void computesSetDifferenceWithEmptyFirstSet() {
+        new Assertion<>(
+            "Can't compute the difference with empty first set",
+            new Diff<>(
+                new SetOf<Integer>(),
+                new SetOf<>(1, 2, 3)
+            ),
+            new HasSize(0)
+        ).affirm();
+    }
+
+    /**
+     * Tests that set difference works with java.util.Set.
+     * @since 0.49
+     */
+    @Test
+    void computesSetDifferenceWithJavaUtilSets() {
+        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 difference of two java.util.Set",
+            new Diff<>(first, second),
+            new HasValues<>(1, 2)
+        ).affirm();
+    }
+
+    /**
+     * Tests that set difference works with iterables.
+     * @since 0.49
+     */
+    @Test
+    void computesSetDifferenceWithIterables() {
+        new Assertion<>(
+            "Can't compute the difference of two iterables",
+            new Diff<>(
+                Collections.singletonList(1),
+                Collections.singletonList(2)
+            ),
+            new HasValues<>(1)
+        ).affirm();
+    }
+
+    /**
+     * Tests that set difference works with iterators.
+     * @since 0.49
+     */
+    @Test
+    void computesSetDifferenceWithIterators() {
+        new Assertion<>(
+            "Can't compute the difference of two iterators",
+            new Diff<>(
+                new SetOf<>(1, 2, 3).iterator(),
+                new SetOf<>(3, 4, 5).iterator()
+            ),
+            new HasValues<>(1, 2)
+        ).affirm();
+    }
+}