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 →