Skip to content

Commit 80ff2dd

Browse files
HashSet vs SortedSet: move to .NET 10, fix RemoveWhere benchmarks, add set order examples (#2318)
1 parent 7c83cd4 commit 80ff2dd

7 files changed

Lines changed: 291 additions & 155 deletions

File tree

‎collections-csharp/HashSetvsSortedSetInCSharp/HashSetvsSortedSetInCSharp/HashSetvsSortedSetInCSharp.csproj‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@
22

33
<PropertyGroup>
44
<OutputType>Exe</OutputType>
5-
<TargetFramework>net6.0</TargetFramework>
5+
<TargetFramework>net10.0</TargetFramework>
66
<ImplicitUsings>enable</ImplicitUsings>
77
<Nullable>enable</Nullable>
88
</PropertyGroup>
99

1010
<ItemGroup>
11-
<PackageReference Include="BenchmarkDotNet" Version="0.13.2" />
11+
<PackageReference Include="BenchmarkDotNet" Version="0.15.8" />
1212
</ItemGroup>
1313

1414
</Project>
Lines changed: 101 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -1,129 +1,135 @@
11
using BenchmarkDotNet.Attributes;
22
using BenchmarkDotNet.Configs;
33

4-
namespace HashSetvsSortedSetInCSharp
4+
namespace HashSetvsSortedSetInCSharp;
5+
6+
[MemoryDiagnoser]
7+
[GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByMethod)]
8+
[Orderer(BenchmarkDotNet.Order.SummaryOrderPolicy.FastestToSlowest)]
9+
[RankColumn]
10+
public class Operations
511
{
6-
[MemoryDiagnoser]
7-
[GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByMethod)]
8-
[Orderer(BenchmarkDotNet.Order.SummaryOrderPolicy.FastestToSlowest)]
9-
[RankColumn]
10-
public class Operations
12+
private readonly List<int> _numList;
13+
private readonly HashSet<int> _hashSet;
14+
private readonly SortedSet<int> _sortedSet;
15+
private readonly int _searchValue;
16+
private HashSet<int> _hashSetCopy = [];
17+
private SortedSet<int> _sortedSetCopy = [];
18+
19+
public Operations()
20+
{
21+
_numList = RandomInts(1000000);
22+
_hashSet = InitializeIntHashSet();
23+
_sortedSet = InitializeIntSortedSet();
24+
_searchValue = int.MaxValue - 1;
25+
}
26+
27+
[Benchmark]
28+
public HashSet<int> InitializeIntHashSet()
1129
{
12-
private readonly List<int> _numList;
13-
private readonly HashSet<int> _hashSet;
14-
private readonly SortedSet<int> _sortedSet;
15-
private readonly int _searchValue;
30+
var hashSet = new HashSet<int>();
1631

17-
public Operations()
32+
foreach (var number in _numList)
1833
{
19-
_numList = RandomInts(1000000);
20-
_hashSet = InitializeIntHashSet();
21-
_sortedSet = InitializeIntSortedSet();
22-
_searchValue = Int32.MaxValue - 1;
34+
hashSet.Add(number);
2335
}
2436

25-
[Benchmark]
26-
public HashSet<int> InitializeIntHashSet()
27-
{
28-
var hashSet = new HashSet<int>();
37+
return hashSet;
38+
}
2939

30-
foreach (var number in _numList)
31-
{
32-
hashSet.Add(number);
33-
}
40+
[Benchmark]
41+
public SortedSet<int> InitializeIntSortedSet()
42+
{
43+
var sortedSet = new SortedSet<int>();
3444

35-
return hashSet;
45+
foreach (var number in _numList)
46+
{
47+
sortedSet.Add(number);
3648
}
3749

38-
[Benchmark]
39-
public SortedSet<int> InitializeIntSortedSet()
40-
{
41-
var sortedSet = new SortedSet<int>();
50+
return sortedSet;
51+
}
4252

43-
foreach (var number in _numList)
44-
{
45-
sortedSet.Add(number);
46-
}
53+
[Benchmark]
54+
public HashSet<int> RemoveElementFromHashSet()
55+
{
56+
_hashSet.Remove(_searchValue);
4757

48-
return sortedSet;
49-
}
58+
return _hashSet;
59+
}
5060

51-
[Benchmark]
52-
public HashSet<int> RemoveElementFromHashSet()
53-
{
54-
_hashSet.Remove(_searchValue);
61+
[Benchmark]
62+
public SortedSet<int> RemoveElementFromSortedSet()
63+
{
64+
_sortedSet.Remove(_searchValue);
5565

56-
return _hashSet;
57-
}
66+
return _sortedSet;
67+
}
5868

59-
[Benchmark]
60-
public HashSet<int> RemoveWhereFromHashSet()
61-
{
62-
_hashSet.RemoveWhere(IsOdd);
69+
[IterationSetup(Targets = [nameof(RemoveWhereFromHashSet), nameof(RemoveWhereFromSortedSet)])]
70+
public void CopySets()
71+
{
72+
_hashSetCopy = new HashSet<int>(_hashSet);
73+
_sortedSetCopy = new SortedSet<int>(_sortedSet);
74+
}
6375

64-
return _hashSet;
65-
}
76+
[Benchmark]
77+
public HashSet<int> RemoveWhereFromHashSet()
78+
{
79+
_hashSetCopy.RemoveWhere(IsOdd);
6680

67-
[Benchmark]
68-
public SortedSet<int> RemoveElementFromSortedSet()
69-
{
70-
_sortedSet.Remove(_searchValue);
81+
return _hashSetCopy;
82+
}
7183

72-
return _sortedSet;
73-
}
84+
[Benchmark]
85+
public SortedSet<int> RemoveWhereFromSortedSet()
86+
{
87+
_sortedSetCopy.RemoveWhere(IsOdd);
7488

75-
[Benchmark]
76-
public SortedSet<int> RemoveWhereFromSortedSet()
77-
{
78-
_sortedSet.RemoveWhere(IsOdd);
89+
return _sortedSetCopy;
90+
}
7991

80-
return _sortedSet;
81-
}
92+
[Benchmark]
93+
public bool SearchSortedSet()
94+
{
95+
return _sortedSet.Contains(_searchValue);
96+
}
8297

83-
[Benchmark]
84-
public bool SearchSortedSet()
85-
{
86-
return _sortedSet.Contains(_searchValue);
87-
}
98+
[Benchmark]
99+
public bool SearchHashSet()
100+
{
101+
return _hashSet.Contains(_searchValue);
102+
}
88103

89-
[Benchmark]
90-
public bool SearchHashSet()
91-
{
92-
return _hashSet.Contains(_searchValue);
93-
}
104+
[Benchmark]
105+
public List<int> SortHashSetElements()
106+
{
107+
return _hashSet.Order().ToList();
108+
}
94109

95-
[Benchmark]
96-
public List<int> SortHashSetElements()
97-
{
98-
var sortElements = _hashSet.OrderBy(element => element).ToList();
99-
100-
return sortElements;
101-
}
110+
[Benchmark]
111+
public List<int> SortSortedSetElements()
112+
{
113+
return _sortedSet.ToList();
114+
}
102115

103-
[Benchmark]
104-
public List<int> SortSortedSetElements()
105-
{
106-
return _sortedSet.ToList();
107-
}
116+
private static List<int> RandomInts(int size)
117+
{
118+
var rand = new Random();
119+
List<int> numbers = [];
108120

109-
private List<int> RandomInts(int size)
121+
for (int i = 0; i < size - 1; i++)
110122
{
111-
var rand = new Random();
112-
var numbers = new List<int>();
113-
114-
for (int i = 0; i < size - 1; i++)
115-
{
116-
numbers.Add(rand.Next());
117-
}
123+
numbers.Add(rand.Next());
124+
}
118125

119-
numbers.Add(Int32.MaxValue - 1);
126+
numbers.Add(int.MaxValue - 1);
120127

121-
return numbers;
122-
}
128+
return numbers;
129+
}
123130

124-
private bool IsOdd(int num)
125-
{
126-
return num % 2 == 1;
127-
}
131+
private static bool IsOdd(int num)
132+
{
133+
return num % 2 == 1;
128134
}
129135
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
using BenchmarkDotNet.Running;
22
using HashSetvsSortedSetInCSharp;
33

4-
var summary = BenchmarkRunner.Run<Operations>();
4+
var summary = BenchmarkRunner.Run<Operations>(args: args);
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
namespace HashSetvsSortedSetInCSharp;
2+
3+
public record Book(string Title, int Year);
4+
5+
public static class SetOrderExamples
6+
{
7+
public static void PrintHashSetAndSortedSetOrder()
8+
{
9+
var hashSet = new HashSet<int> { 1, 2, 3, 4, 5 };
10+
hashSet.Remove(2);
11+
hashSet.Add(6);
12+
13+
Console.WriteLine(string.Join(", ", hashSet));
14+
15+
var sortedSet = new SortedSet<int> { 5, 1, 4, 2, 3 };
16+
sortedSet.Remove(2);
17+
sortedSet.Add(6);
18+
19+
Console.WriteLine(string.Join(", ", sortedSet));
20+
}
21+
22+
public static OrderedDictionary<string, bool> TrackPagesInVisitOrder()
23+
{
24+
var visited = new OrderedDictionary<string, bool>();
25+
visited.TryAdd("home", true);
26+
visited.TryAdd("pricing", true);
27+
visited.TryAdd("home", true);
28+
visited.TryAdd("docs", true);
29+
30+
Console.WriteLine(string.Join(", ", visited.Keys));
31+
32+
return visited;
33+
}
34+
35+
public static SortedSet<Book> SortBooksByYear()
36+
{
37+
var byYear = Comparer<Book>.Create((a, b) => a.Year.CompareTo(b.Year));
38+
39+
var sortedBooks = new SortedSet<Book>(byYear)
40+
{
41+
new("Dune", 1965),
42+
new("The Moon Is a Harsh Mistress", 1966),
43+
new("Flowers for Algernon", 1966)
44+
};
45+
46+
Console.WriteLine(sortedBooks.Count);
47+
48+
return sortedBooks;
49+
}
50+
51+
public static HashSet<Book> BooksInHashSet()
52+
{
53+
return
54+
[
55+
new("Dune", 1965),
56+
new("The Moon Is a Harsh Mistress", 1966),
57+
new("Flowers for Algernon", 1966)
58+
];
59+
}
60+
}

‎collections-csharp/HashSetvsSortedSetInCSharp/HashSetvsSortedSetInCSharpTests/HashSetvsSortedSetInCSharpTests.csproj‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
4-
<TargetFramework>net6.0</TargetFramework>
4+
<TargetFramework>net10.0</TargetFramework>
55
<ImplicitUsings>enable</ImplicitUsings>
66
<Nullable>enable</Nullable>
77

88
<IsPackable>false</IsPackable>
99
</PropertyGroup>
1010

1111
<ItemGroup>
12-
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" />
13-
<PackageReference Include="MSTest.TestAdapter" Version="2.2.8" />
14-
<PackageReference Include="MSTest.TestFramework" Version="2.2.8" />
15-
<PackageReference Include="coverlet.collector" Version="3.1.2" />
12+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.11.0" />
13+
<PackageReference Include="MSTest.TestAdapter" Version="4.5.1" />
14+
<PackageReference Include="MSTest.TestFramework" Version="4.5.1" />
15+
<PackageReference Include="coverlet.collector" Version="10.1.0" />
1616
</ItemGroup>
1717

1818
<ItemGroup>

0 commit comments

Comments
 (0)