Skip to content

Instantly share code, notes, and snippets.

@palladin
Last active August 14, 2023 11:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save palladin/cdb8e38f27a6a55674503561a18d940b to your computer and use it in GitHub Desktop.
Save palladin/cdb8e38f27a6a55674503561a18d940b to your computer and use it in GitHub Desktop.
Composable Index
using System.Linq;
public static class Index
{
public static Index<TKey, TValue> Create<TKey, TValue>()
where TKey : notnull
{
var keyMap = new Dictionary<TKey, HashSet<TValue>>();
Action<TKey, TValue> add = (key, value) =>
{
if (key is not null)
{
if (keyMap.ContainsKey(key))
keyMap[key].Add(value);
else
keyMap.Add(key, new HashSet<TValue> { value });
}
};
Action<List<HashSet<TValue>>, TKey> collect = (values, key) =>
{
if (key is not null)
{
if (keyMap.ContainsKey(key))
values.Add(keyMap[key]);
else
values.Add(new HashSet<TValue>());
}
};
return new Index<TKey, TValue>(add, collect);
}
public static Index<(TKey1, TKey2), TValue> Compose<TKey1, TKey2, TValue>(this Index<TKey1, TValue> index1, Index<TKey2, TValue> index2)
{
Action<(TKey1, TKey2), TValue> add = (key, v) =>
{
index1.Add(key.Item1, v);
index2.Add(key.Item2, v);
};
Action<List<HashSet<TValue>>, (TKey1, TKey2)> collect = (values, key) =>
{
index1.Collect(values, key.Item1);
index2.Collect(values, key.Item2);
};
return new Index<(TKey1, TKey2), TValue>(add, collect);
}
}
public class Index<TKey, TValue>
{
private readonly Action<TKey, TValue> _add;
private readonly Action<List<HashSet<TValue>>, TKey> _collect;
public Action<TKey, TValue> Add => _add;
public Action<List<HashSet<TValue>>, TKey> Collect => _collect;
public Index(Action<TKey, TValue> add, Action<List<HashSet<TValue>>, TKey> collect)
{
_add = add;
_collect = collect;
}
public List<TValue> Match(TKey key)
{
var collectValues = new List<HashSet<TValue>>();
_collect(collectValues, key);
collectValues = collectValues.OrderBy(x => x.Count).ToList();
if (collectValues.Any(x => x.Count == 0))
return new List<TValue>();
if (collectValues.Count == 0)
return new List<TValue>();
else if (collectValues.Count == 1)
return collectValues[0].ToList();
else
{
var result = new HashSet<TValue>();
foreach (var value in collectValues[0])
result.Add(value);
foreach (var values in collectValues.Skip(1))
{
foreach (var value in result)
{
if (!values.Contains(value))
result.Remove(value);
}
}
return result.ToList();
}
}
}
public static class Program
{
public static void Main(string[] args)
{
var values = new (string, string, int)[] { ("1", "2", 1), ("", "2", 2), ("1", "", 3) };
var index1 = Index.Create<string, int>();
var index2 = Index.Create<string, int>();
var index12 = index1.Compose(index2);
foreach (var (key1, key2, value) in values)
{
index12.Add((key1, key2), value);
}
var result = index12.Match(("1", "2"));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment