my advent of code solutions
1using System.Numerics;
2
3namespace Solutions;
4
5public static class Extensions
6{
7 /// <summary>
8 /// <c>string.Join</c> Wrapper
9 /// </summary>
10 /// <param name="enumerable"></param>
11 /// <param name="delimiter"></param>
12 /// <typeparam name="T"></typeparam>
13 /// <returns></returns>
14 public static string Join<T>(this IEnumerable<T> enumerable, string delimiter = "") =>
15 string.Join(delimiter, enumerable);
16
17 /// <summary>
18 /// Loop over a sequence with an optional number of times.
19 /// </summary>
20 /// <param name="sequence"></param>
21 /// <param name="count"></param>
22 /// <typeparam name="T"></typeparam>
23 /// <returns></returns>
24 public static IEnumerable<T> Repeat<T>(this IEnumerable<T> sequence, int? count = null)
25 {
26 while (count == null || count-- > 0)
27 // ReSharper disable once PossibleMultipleEnumeration
28 foreach (var item in sequence)
29 yield return item;
30 }
31
32 /// <summary>
33 /// Increased accuracy for stopwatch based on frequency.
34 /// </summary>
35 /// <param name="stopwatch"></param>
36 /// <returns></returns>
37 public static double ScaleMilliseconds(this Stopwatch stopwatch) =>
38 1_000 * stopwatch.ElapsedTicks / (double)Stopwatch.Frequency;
39
40 /// <summary>
41 /// Given an array, it returns a rotated copy.
42 /// </summary>
43 /// <param name="array">The two-dimensional jagged array to rotate.</param>
44 public static T[][] Rotate<T>(this T[][] array)
45 {
46 var result = new T[array[0].Length][];
47 for (var i = 0; i < result.Length; i++)
48 result[i] = new T[array.Length];
49
50 for (var i = 0; i < array.Length; i++)
51 for (var j = 0; j < array[i].Length; j++)
52 result[i][j] = array[array.Length - j - 1][i];
53
54 return result;
55 }
56
57 /// <summary>
58 /// Given a jagged array, it returns a diagonally flipped copy.
59 /// </summary>
60 /// <param name="array">The two-dimensional jagged array to flip.</param>
61 public static T[][] FlipHorizontally<T>(this IEnumerable<T[]> array) =>
62 array.Select(x => x.Reverse().ToArray()).ToArray();
63
64 /// <summary>
65 /// Does the <see cref="Range"/> include a given int?
66 /// </summary>
67 /// <param name="range"></param>
68 /// <param name="i"></param>
69 /// <returns></returns>
70 public static bool Contains(this Range range, int i) =>
71 i >= range.Start.Value && i <= range.End.Value;
72
73 /// <summary>
74 /// Does <paramref name="r1"/> contain the entire range of <paramref name="r2"/>?
75 /// </summary>
76 /// <param name="r1"></param>
77 /// <param name="r2"></param>
78 /// <returns></returns>
79 public static bool Contains(this Range r1, Range r2) =>
80 r1.Start.Value <= r2.Start.Value && r1.End.Value >= r2.End.Value;
81
82 /// <summary>
83 /// Do <paramref name="r1"/> and <paramref name="r2"/> overlap?
84 /// </summary>
85 /// <param name="r1"></param>
86 /// <param name="r2"></param>
87 /// <returns></returns>
88 public static bool Overlaps(this Range r1, Range r2) =>
89 r1.Start.Value <= r2.End.Value && r1.End.Value >= r2.Start.Value &&
90 r2.Start.Value <= r1.End.Value && r2.End.Value >= r1.Start.Value;
91
92 /// <summary>
93 /// Creates a new BigInteger from a binary (Base2) string
94 /// Based on <a href="https://gist.github.com/mjs3339/73042bc0e717f98796ee9fa131e458d4">mjs3339's gist</a>
95 /// </summary>
96 public static BigInteger BigIntegerFromBinaryString(this string binaryValue)
97 {
98 BigInteger res = 0;
99 if (binaryValue.Count(b => b == '1') + binaryValue.Count(b => b == '0') != binaryValue.Length) return res;
100 foreach (var c in binaryValue)
101 {
102 res <<= 1;
103 res += c == '1' ? 1 : 0;
104 }
105
106 return res;
107 }
108
109 /// <summary>
110 /// Generate all permutations of an Enumerable.
111 /// </summary>
112 /// <param name="list"></param>
113 /// <typeparam name="T"></typeparam>
114 /// <returns></returns>
115 public static IEnumerable<IEnumerable<T>> Permute<T>(this IEnumerable<T> list)
116 {
117 var array = list as T[] ?? list.ToArray();
118 return array.Length == 1
119 ? [array]
120 : array.SelectMany(t => Permute(array.Where(x => !x!.Equals(t))), (v, p) => p.Prepend(v));
121 }
122
123 /// <summary>
124 /// Raise an integer to a given <paramref name="power"/>.
125 /// </summary>
126 /// <param name="i"></param>
127 /// <param name="power"></param>
128 /// <returns></returns>
129 public static int Pow(this int i, int power)
130 {
131 var pow = (uint)power;
132 var ret = 1;
133 while (pow != 0)
134 {
135 if ((pow & 1) == 1) ret *= i;
136 i *= i;
137 pow >>= 1;
138 }
139
140 return ret;
141 }
142
143 /// <summary>
144 /// Attach the index of each element.
145 /// </summary>
146 /// <param name="source"></param>
147 /// <typeparam name="T"></typeparam>
148 /// <returns></returns>
149 public static IEnumerable<KeyValuePair<int, T>> Indexed<T>(this IEnumerable<T> source) =>
150 source.Select((t, i) => new KeyValuePair<int, T>(i, t));
151
152 /// <summary>
153 /// Wrapper for KeyValuePair to enable passing delegates.
154 /// </summary>
155 /// <param name="source"></param>
156 /// <param name="func"></param>
157 /// <typeparam name="TKey"></typeparam>
158 /// <typeparam name="TValue"></typeparam>
159 /// <returns></returns>
160 public static IEnumerable<KeyValuePair<TKey, TValue>> WhereValue<TKey, TValue>(
161 this IEnumerable<KeyValuePair<TKey, TValue>> source, Func<TValue, bool> func) =>
162 source.Where(pair => func(pair.Value));
163
164 /// <summary>
165 /// Compute the Hamming distance between two strings.
166 /// </summary>
167 /// <param name="s1"></param>
168 /// <param name="other"></param>
169 /// <returns></returns>
170 /// <exception cref="Exception"></exception>
171 public static int HammingDistance(this string s1, string other)
172 {
173 if (s1.Length != other.Length) throw new("Strings must be equal length.");
174 return s1.Zip(other).Count(s => s.First != s.Second);
175 }
176}