Two-way key value collection [duplicate]
Two-way key value collection [duplicate]
This question already has an answer here:
Is there a collection in C# working like dictionary with multiple keys allowing bidirectional access? For example:
Collection<int, string> a = new Collection<int, string>();
a.Add(1, "a");
a.Add(1, "b");
a.Add(2, "a");
a.Get(1);//returns ["a", "b"]
a.InverseGet("a"); //returns [1, 2]
This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.
A simple
.Where()
would do the job if you don't care about performance that much– Panagiotis Kanavos
Sep 4 '18 at 8:26
.Where()
Another option is the DataTable. It doesn't care about directions and can use indexes to improve performance
– Panagiotis Kanavos
Sep 4 '18 at 8:28
You should use a list of key value pairs.
var collection = new List<KeyValuePair<int, string>>();
This you can query with LINQ easily.– ChristianMurschall
Sep 4 '18 at 8:28
var collection = new List<KeyValuePair<int, string>>();
@Linuxrocks there's no need to use a KVP, an array of tuples will work just as well
– Panagiotis Kanavos
Sep 4 '18 at 8:29
2 Answers
2
Using Tuple List<Tuple<int,string>>
to allow a collection with the same key and LINQ
to make a query Where to your collection
List<Tuple<int,string>>
LINQ
For example,
List<Tuple<int,string>> list = new List<Tuple<int,string>>();
list.Add(Tuple.Create(23, "Foo"));
list.Add(Tuple.Create(23, "Bar"));
list.Add(Tuple.Create(25, "Bar"));
var keys = list.Where(x=> x.Item1 == 23).Select(x=> x.Item2); // FOO, BAR
var values = list.Where(x=> x.Item2 == "Bar").Select(x=> x.Item1); ; // 23, 25
Here is a solution that gives you the performance of a dictionary lookup in both directions. I assume that you want to ignore duplicate tuples and the default comparer is sufficient. Implementing the other operations like Remove is left as an exercise for the reader
public class TwoWayCollection<A, B>
private Dictionary<A, HashSet<B>> byADictionary = new Dictionary<A, HashSet<B>>();
private Dictionary<B, HashSet<A>> byBDictionary = new Dictionary<B, HashSet<A>>();
public IEnumerable<B> Get(A a)
return byADictionary[a];
public IEnumerable<A> InverseGet(B b)
return byBDictionary[b];
public void Add(A a, B b)
if (!byADictionary.ContainsKey(a))
byADictionary[a] = new HashSet<B>();
byADictionary[a].Add(b);
if (!byBDictionary.ContainsKey(b))
byBDictionary[b] = new HashSet<A>();
byBDictionary[b].Add(a);
Then to use it is literally your proposed code. Both Get and InverseGet approach O(1) as per dictionary
TwoWayCollection<int, string> a = new TwoWayCollection<int, string>();
a.Add(1, "a");
a.Add(1, "b");
a.Add(2, "a");
a.Get(1); //returns ["a", "b"]
a.InverseGet("a"); //returns [1, 2]
You have LINQ for that.
– SeM
Sep 4 '18 at 8:25