Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/HeuristicLab.Collections/3.3/BidirectionalLookup.cs @ 17609

Last change on this file since 17609 was 17180, checked in by swagner, 5 years ago

#2875: Removed years in copyrights

File size: 7.8 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using System.Collections.Generic;
24using System.Linq;
25using HEAL.Attic;
26
27namespace HeuristicLab.Collections {
28  [StorableType("30981E2A-09AD-49F4-964B-4C20B210116C")]
29  [Serializable]
30  public class BidirectionalLookup<TFirst, TSecond> {
31    [Storable]
32    private readonly Dictionary<TFirst, HashSet<TSecond>> firstToSecond;
33    [Storable]
34    private readonly Dictionary<TSecond, HashSet<TFirst>> secondToFirst;
35
36    [StorableConstructor]
37    protected BidirectionalLookup(StorableConstructorFlag _) : base() { }
38    public BidirectionalLookup() {
39      firstToSecond = new Dictionary<TFirst, HashSet<TSecond>>();
40      secondToFirst = new Dictionary<TSecond, HashSet<TFirst>>();
41    }
42    public BidirectionalLookup(IEqualityComparer<TFirst> firstComparer) {
43      firstToSecond = new Dictionary<TFirst, HashSet<TSecond>>(firstComparer);
44      secondToFirst = new Dictionary<TSecond, HashSet<TFirst>>();
45    }
46    public BidirectionalLookup(IEqualityComparer<TSecond> secondComparer) {
47      firstToSecond = new Dictionary<TFirst, HashSet<TSecond>>();
48      secondToFirst = new Dictionary<TSecond, HashSet<TFirst>>(secondComparer);
49    }
50    public BidirectionalLookup(IEqualityComparer<TFirst> firstComparer, IEqualityComparer<TSecond> secondComparer) {
51      firstToSecond = new Dictionary<TFirst, HashSet<TSecond>>(firstComparer);
52      secondToFirst = new Dictionary<TSecond, HashSet<TFirst>>(secondComparer);
53    }
54
55    #region Properties
56    public int CountFirst {
57      get { return firstToSecond.Count; }
58    }
59
60    public int CountSecond {
61      get { return secondToFirst.Count; }
62    }
63
64    public IEnumerable<TFirst> FirstKeys {
65      get { return firstToSecond.Keys.AsEnumerable(); }
66    }
67
68    public IEnumerable<TSecond> SecondKeys {
69      get { return secondToFirst.Keys.AsEnumerable(); }
70    }
71
72    public IEnumerable<IGrouping<TFirst, TSecond>> FirstEnumerable {
73      get { return firstToSecond.Select(x => new StorableGrouping<TFirst, TSecond>(x.Key, x.Value, secondToFirst.Comparer)); }
74    }
75
76    public IEnumerable<IGrouping<TSecond, TFirst>> SecondEnumerable {
77      get { return secondToFirst.Select(x => new StorableGrouping<TSecond, TFirst>(x.Key, x.Value, firstToSecond.Comparer)); }
78    }
79    #endregion
80
81    #region Methods
82    public void Add(TFirst firstValue, TSecond secondValue) {
83      HashSet<TSecond> firstSet;
84      if (!firstToSecond.TryGetValue(firstValue, out firstSet)) {
85        firstSet = new HashSet<TSecond>(secondToFirst.Comparer);
86        firstToSecond[firstValue] = firstSet;
87      }
88      HashSet<TFirst> secondSet;
89      if (!secondToFirst.TryGetValue(secondValue, out secondSet)) {
90        secondSet = new HashSet<TFirst>(firstToSecond.Comparer);
91        secondToFirst[secondValue] = secondSet;
92      }
93      firstSet.Add(secondValue);
94      secondSet.Add(firstValue);
95    }
96
97    public void AddRangeFirst(TFirst firstValue, IEnumerable<TSecond> secondValues) {
98      HashSet<TSecond> firstSet;
99      if (!firstToSecond.TryGetValue(firstValue, out firstSet)) {
100        firstSet = new HashSet<TSecond>(secondToFirst.Comparer);
101        firstToSecond[firstValue] = firstSet;
102      }
103      foreach (var s in secondValues) {
104        HashSet<TFirst> secondSet;
105        if (!secondToFirst.TryGetValue(s, out secondSet)) {
106          secondSet = new HashSet<TFirst>(firstToSecond.Comparer);
107          secondToFirst[s] = secondSet;
108        }
109        firstSet.Add(s);
110        secondSet.Add(firstValue);
111      }
112    }
113
114    public void AddRangeSecond(TSecond secondValue, IEnumerable<TFirst> firstValues) {
115      HashSet<TFirst> secondSet;
116      if (!secondToFirst.TryGetValue(secondValue, out secondSet)) {
117        secondSet = new HashSet<TFirst>(firstToSecond.Comparer);
118        secondToFirst[secondValue] = secondSet;
119      }
120      foreach (var f in firstValues) {
121        HashSet<TSecond> firstSet;
122        if (!firstToSecond.TryGetValue(f, out firstSet)) {
123          firstSet = new HashSet<TSecond>(secondToFirst.Comparer);
124          firstToSecond[f] = firstSet;
125        }
126        firstSet.Add(secondValue);
127        secondSet.Add(f);
128      }
129    }
130
131    public bool ContainsFirst(TFirst firstValue) {
132      return firstToSecond.ContainsKey(firstValue);
133    }
134
135    public bool ContainsSecond(TSecond secondValue) {
136      return secondToFirst.ContainsKey(secondValue);
137    }
138
139    public IEnumerable<TSecond> GetByFirst(TFirst firstValue) {
140      return firstToSecond[firstValue];
141    }
142
143    public IEnumerable<TFirst> GetBySecond(TSecond secondValue) {
144      return secondToFirst[secondValue];
145    }
146
147    public void SetByFirst(TFirst firstValue, IEnumerable<TSecond> secondValues) {
148      RemoveByFirst(firstValue);
149      AddRangeFirst(firstValue, secondValues);
150    }
151
152    public void SetBySecond(TSecond secondValue, IEnumerable<TFirst> firstValues) {
153      RemoveBySecond(secondValue);
154      AddRangeSecond(secondValue, firstValues);
155    }
156
157    public void RemovePair(TFirst first, TSecond second) {
158      if (!ContainsFirst(first) || !ContainsSecond(second)) return;
159      firstToSecond[first].Remove(second);
160      if (!firstToSecond[first].Any()) firstToSecond.Remove(first);
161      secondToFirst[second].Remove(first);
162      if (!secondToFirst[second].Any()) secondToFirst.Remove(second);
163    }
164
165    public void RemoveByFirst(TFirst firstValue) {
166      if (!ContainsFirst(firstValue)) return;
167      var secondValues = firstToSecond[firstValue].ToArray();
168      firstToSecond.Remove(firstValue);
169      foreach (var s in secondValues) {
170        secondToFirst[s].Remove(firstValue);
171        if (!secondToFirst[s].Any()) secondToFirst.Remove(s);
172      }
173    }
174
175    public void RemoveBySecond(TSecond secondValue) {
176      if (!ContainsSecond(secondValue)) return;
177      var firstValues = secondToFirst[secondValue].ToArray();
178      secondToFirst.Remove(secondValue);
179      foreach (var f in firstValues) {
180        firstToSecond[f].Remove(secondValue);
181        if (!firstToSecond[f].Any()) firstToSecond.Remove(f);
182      }
183    }
184
185    public void Clear() {
186      firstToSecond.Clear();
187      secondToFirst.Clear();
188    }
189    #endregion
190
191    [StorableType("AF0C6143-9031-43CF-8952-49FE8089ACD2")]
192    private class StorableGrouping<TKey, TValue> : IGrouping<TKey, TValue> {
193
194      [Storable]
195      private readonly TKey key;
196      [Storable]
197      private readonly HashSet<TValue> values;
198
199      [StorableConstructor]
200      protected StorableGrouping(StorableConstructorFlag _) : base() { }
201
202      public StorableGrouping(TKey key, IEnumerable<TValue> values, IEqualityComparer<TValue> comparer) {
203        this.key = key;
204        this.values = new HashSet<TValue>(values, comparer);
205      }
206
207      public TKey Key {
208        get { return key; }
209      }
210
211      public IEnumerator<TValue> GetEnumerator() {
212        return values.GetEnumerator();
213      }
214
215      System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
216        return GetEnumerator();
217      }
218    }
219  }
220}
Note: See TracBrowser for help on using the repository browser.