Skip to content

List Set Operations — Java source

Compute the union, intersection, difference, or symmetric difference of two newline-separated lists. Deduped results with optional trim and case-insensitive matching. Runs entirely in your browser, with a shareable link.

This is the Java implementation — the same logic the interactive tool runs, in a shareable, citable form.

// list-set-ops — union / intersection / difference / symmetric difference of
// two newline-separated lists. Java port (canonical TS:
// src/lib/list-set-ops.ts; Go twin: cli/list-set-ops). HashSet is the
// membership set; trim defaults on like the TS `trim !== false`. split with
// limit -1 keeps trailing empty lines so trim-then-drop matches the TS split.
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;

public class ListSetOps {
    public static final class SetOptions {
        final boolean caseInsensitive;
        final boolean trim; // the TS default (omitted -> trim on)

        public SetOptions() { this(false, true); }
        public SetOptions(boolean caseInsensitive) { this(caseInsensitive, true); }
        SetOptions(boolean caseInsensitive, boolean trim) {
            this.caseInsensitive = caseInsensitive;
            this.trim = trim;
        }
    }

    // Folded membership key: lowercase copy when case-insensitive, else the item.
    static String key(String s, SetOptions o) {
        return o.caseInsensitive ? s.toLowerCase(Locale.ROOT) : s;
    }

    // Split a newline list into a deduped list (first-seen casing kept).
    static List<String> parseList(String input, SetOptions o) {
        List<String> items = new ArrayList<>();
        if (input.isEmpty()) return items; // empty input = no items
        Set<String> seen = new HashSet<>();
        for (String item : input.split("\n", -1)) {
            if (o.trim) {
                item = item.strip();
                if (item.isEmpty()) continue;
            }
            if (seen.add(key(item, o))) items.add(item);
        }
        return items;
    }
    // Compute a set op over two lists; the result is "\n"-joined.
    public static String setOps(String a, String b, String op, SetOptions o) {
        List<String> listA = parseList(a, o), listB = parseList(b, o);
        Set<String> keysA = new HashSet<>(), keysB = new HashSet<>();
        for (String s : listA) keysA.add(key(s, o));
        for (String s : listB) keysB.add(key(s, o));
        List<String> out = new ArrayList<>();
        switch (op) {
            case "union" -> { // every unique item, a then b
                Set<String> seen = new HashSet<>();
                for (String s : listA) if (seen.add(key(s, o))) out.add(s);
                for (String s : listB) if (seen.add(key(s, o))) out.add(s);
            }
            case "intersect" -> { // items present in both (a's order/casing)
                for (String s : listA) if (keysB.contains(key(s, o))) out.add(s);
            }
            case "difference" -> { // items in a not present in b
                for (String s : listA) if (!keysB.contains(key(s, o))) out.add(s);
            }
            case "symmetricDifference" -> { // exactly one list, a-only then b-only
                for (String s : listA) if (!keysB.contains(key(s, o))) out.add(s);
                for (String s : listB) if (!keysA.contains(key(s, o))) out.add(s);
            }
            default -> {} // unknown op -> ""
        }
        return String.join("\n", out);
    }
    public static void main(String[] args) {
        String A = "apple\nbanana\ncherry", B = "banana\ncherry\ndate";
        System.out.println(setOps(A, B, "union", new SetOptions()));               // apple\nbanana\ncherry\ndate
        System.out.println(setOps(A, B, "intersect", new SetOptions()));           // banana\ncherry
        System.out.println(setOps(A, B, "difference", new SetOptions()));          // apple
        System.out.println(setOps(A, B, "symmetricDifference", new SetOptions())); // apple\ndate
        // case-folded compare, first-seen original casing emitted
        System.out.println(setOps("HELLO", "hello", "intersect", new SetOptions(true))); // HELLO
    }
}

Also available in 13 other languages

Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →