Skip to content

List Set Operations — C# 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 C# 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. C# port (canonical TS:
// src/lib/list-set-ops.ts; Go twin: cli/list-set-ops). HashSet<string> is the
// membership set; trim defaults on like the TS `trim !== false`.
using System;
using System.Collections.Generic;

public static class ListSetOps
{
    public sealed class SetOptions
    {
        public bool CaseInsensitive;
        public bool Trim = true; // the TS default (omitted -> trim on)
    }

    // Folded membership key: lowercase copy when case-insensitive, else the item.
    private static string Key(string s, SetOptions o) =>
        o.CaseInsensitive ? s.ToLowerInvariant() : s;
    // Split a newline list into a deduped list (first-seen casing kept).
    private static List<string> ParseList(string input, SetOptions o)
    {
        var items = new List<string>();
        if (input == "") return items; // empty input = no items
        var seen = new HashSet<string>();
        foreach (var raw in input.Split('\n'))
        {
            var item = raw;
            if (o.Trim)
            {
                item = item.Trim();
                if (item.Length == 0) 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 Run(string a, string b, string op, SetOptions o = null)
    {
        if (o == null) o = new SetOptions();
        var listA = ParseList(a, o);
        var listB = ParseList(b, o);
        var keysA = new HashSet<string>();
        var keysB = new HashSet<string>();
        foreach (var s in listA) keysA.Add(Key(s, o));
        foreach (var s in listB) keysB.Add(Key(s, o));

        var res = new List<string>();
        switch (op)
        {
            case "union": // every unique item, a then b
                var seen = new HashSet<string>();
                foreach (var s in listA) if (seen.Add(Key(s, o))) res.Add(s);
                foreach (var s in listB) if (seen.Add(Key(s, o))) res.Add(s);
                break;
            case "intersect": // items present in both (a's order/casing)
                foreach (var s in listA) if (keysB.Contains(Key(s, o))) res.Add(s);
                break;
            case "difference": // items in a not present in b
                foreach (var s in listA) if (!keysB.Contains(Key(s, o))) res.Add(s);
                break;
            case "symmetricDifference": // exactly one list, a-only then b-only
                foreach (var s in listA) if (!keysB.Contains(Key(s, o))) res.Add(s);
                foreach (var s in listB) if (!keysA.Contains(Key(s, o))) res.Add(s);
                break;
            default: break; // unknown op -> ""
        }
        return string.Join("\n", res);
    }
    public static void Main()
    {
        const string A = "apple\nbanana\ncherry", B = "banana\ncherry\ndate";
        Console.WriteLine(Run(A, B, "union"));               // apple\nbanana\ncherry\ndate
        Console.WriteLine(Run(A, B, "intersect"));           // banana\ncherry
        Console.WriteLine(Run(A, B, "difference"));          // apple
        Console.WriteLine(Run(A, B, "symmetricDifference")); // apple\ndate
        // case-folded compare, first-seen original casing emitted
        Console.WriteLine(Run("HELLO", "hello", "intersect", new SetOptions { CaseInsensitive = 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 →