@@ -29,6 +29,11 @@ public static void RunTests()
29
29
CorrectNREAfterEachRead = new int [ ] { 'a' , - 1 , 'b' , 'b' } ,
30
30
} ,
31
31
new TestCase
32
+ {
33
+ InputAsString = "ccaba" ,
34
+ CorrectNREAfterEachRead = new int [ ] { 'c' , - 1 , 'a' , 'b' , 'b' } ,
35
+ } ,
36
+ new TestCase
32
37
{
33
38
InputAsString = String . Empty ,
34
39
CorrectNREAfterEachRead = new int [ ] { - 1 } ,
@@ -57,40 +62,164 @@ public static void RunTests()
57
62
Console . WriteLine ( $ "For the stream: { testCases [ i ] . InputAsString } ") ;
58
63
//Console.WriteLine($"The correct result is: {testCases[i].CorrectNREAfterEachRead}");
59
64
60
- var testCaseResult = PrintFirstNRE ( testCases [ i ] . InputAsStream ) ;
65
+ PrintFirstNRE_ForVideo ( testCases [ i ] . InputAsStream ) ;
61
66
62
- string resultMessage ;
67
+ // string resultMessage;
63
68
64
- if ( Enumerable . SequenceEqual ( testCaseResult , testCases [ i ] . CorrectNREAfterEachRead ) )
65
- {
66
- resultMessage = "SUCCESS" ;
67
- }
68
- else
69
- {
70
- ++ testOopsCount ;
71
- resultMessage = "OOPS" ;
72
- }
69
+ // if (Enumerable.SequenceEqual(testCaseResult, testCases[i].CorrectNREAfterEachRead))
70
+ // {
71
+ // resultMessage = "SUCCESS";
72
+ // }
73
+ // else
74
+ // {
75
+ // ++testOopsCount;
76
+ // resultMessage = "OOPS";
77
+ // }
73
78
74
- Console . WriteLine ( $ "{ resultMessage } !") ;
79
+ // Console.WriteLine($"{resultMessage}!");
75
80
//Console.WriteLine($"Your answer is: {testCaseResult}");
76
81
}
77
82
78
- var testCount = testCases . Count ;
79
- var testSuccessCount = testCount - testOopsCount ;
83
+ //var testCount = testCases.Count;
84
+ //var testSuccessCount = testCount - testOopsCount;
85
+
86
+ //Console.WriteLine($"\n\nOut of {testCount} tests total,\n");
87
+ //Console.WriteLine($"{testSuccessCount}/{testCount} tests succeeded, and");
88
+ //Console.WriteLine($"{testOopsCount}/{testCount} tests oopsed.\n");
89
+
90
+ //if (testOopsCount == 0)
91
+ //{
92
+ // Console.WriteLine($"YAY! All tests succeeded! :D\n");
93
+ //}
94
+ }
95
+
96
+
97
+ const int NO_NRE = - 1 ;
98
+
99
+ const int LETTER_COUNT = 'z' - 'a' ;
100
+
101
+ public static void PrintFirstNRE_ForVideo ( StreamReader sr )
102
+ {
103
+ if ( sr == null )
104
+ throw new ArgumentNullException ( "Parameter StreamReader sr is null." ) ;
105
+
106
+ if ( sr . EndOfStream == true )
107
+ Console . WriteLine (
108
+ $ "No letters found in stream.\n " +
109
+ $ "No non-repeating letters. { NO_NRE } ") ;
110
+
111
+ var letterTracker = new OrderedLetter_ForVideo [ LETTER_COUNT ] ;
112
+
113
+ for ( var i = 0 ; i < LETTER_COUNT ; ++ i )
114
+ letterTracker [ i ] = new OrderedLetter_ForVideo ( ) ;
115
+
116
+ while ( sr . EndOfStream == false )
117
+ {
118
+ var currLetter = sr . Read ( ) ;
119
+ ValidateLetter ( currLetter ) ;
120
+
121
+ Console . WriteLine (
122
+ $ "Reading '{ Convert . ToChar ( currLetter ) } ' from stream.") ;
123
+
124
+ letterTracker [ currLetter - 'a' ] . LogAsRead ( ) ;
125
+
126
+ var currFirstNRE = FindCurrentFirstNRE_ForVideo ( letterTracker ) ;
127
+
128
+ if ( currFirstNRE == NO_NRE )
129
+ Console . WriteLine ( $ "No non-repeating letters. { NO_NRE } ") ;
130
+ else
131
+ Console . WriteLine ( $ "First non-repeating letter so far is: { Convert . ToChar ( currFirstNRE ) } ") ;
132
+ }
133
+ }
134
+ public static void ValidateLetter ( int letter )
135
+ {
136
+ if ( letter < 'a' || letter > 'z' )
137
+ throw new ArgumentException (
138
+ "Stream may contain only letters between 'a' and 'z', inclusive." ) ;
139
+ }
140
+ private class OrderedLetter_ForVideo
141
+ {
142
+ public int FirstSeenOrder { get ; private set ; }
143
+ public bool DoesRepeat { get ; private set ; }
144
+ public OrderedLetter_ForVideo ( )
145
+ {
146
+ FirstSeenOrder = NOT_SEEN ;
147
+ DoesRepeat = false ;
148
+ }
149
+ private const int NOT_SEEN = - 2 ;
150
+
151
+ private static int nextSeenOrderValue = 0 ;
152
+ public void LogAsRead ( )
153
+ {
154
+ if ( FirstSeenOrder < 0 )
155
+ FirstSeenOrder = nextSeenOrderValue ++ ;
156
+ else
157
+ DoesRepeat = true ;
158
+ }
159
+ }
160
+ private static int FindCurrentFirstNRE_ForVideo ( OrderedLetter_ForVideo [ ] letterTracker )
161
+ {
162
+ var allCurrentNREQuery = letterTracker
163
+ . Where ( ol => ol . FirstSeenOrder >= 0 )
164
+ . Where ( ol => ol . DoesRepeat == false ) ;
80
165
81
- Console . WriteLine ( $ "\n \n Out of { testCount } tests total,\n ") ;
82
- Console . WriteLine ( $ "{ testSuccessCount } /{ testCount } tests succeeded, and") ;
83
- Console . WriteLine ( $ "{ testOopsCount } /{ testCount } tests oopsed.\n ") ;
166
+ if ( allCurrentNREQuery . Count ( ) == 0 )
167
+ return NO_NRE ;
84
168
85
- if ( testOopsCount == 0 )
169
+ var newFirstNRE = allCurrentNREQuery
170
+ . OrderBy ( ol => ol . FirstSeenOrder )
171
+ . First ( ) ;
172
+
173
+ for ( var i = 0 ; i < LETTER_COUNT ; ++ i )
86
174
{
87
- Console . WriteLine ( $ "YAY! All tests succeeded! :D\n ") ;
175
+ if ( ReferenceEquals ( letterTracker [ i ] , newFirstNRE ) )
176
+ return 'a' + i ;
88
177
}
178
+
179
+ throw new ArgumentException (
180
+ "An element in letterTracker met the query criteria," +
181
+ "but that element isn't in letterTracker? Wat." ) ;
89
182
}
90
183
91
184
92
185
93
186
187
+
188
+
189
+
190
+
191
+
192
+
193
+
194
+
195
+
196
+
197
+
198
+
199
+
200
+
201
+
202
+
203
+
204
+
205
+
206
+
207
+
208
+
209
+
210
+
211
+
212
+
213
+
214
+
215
+
216
+
217
+
218
+
219
+
220
+
221
+
222
+
94
223
private class OrderedLetter
95
224
{
96
225
private static int nextSeenOrderValue = 0 ;
@@ -107,7 +236,7 @@ public OrderedLetter()
107
236
// logic handles it seperately
108
237
// Returns true if this is a new sighting of the letter
109
238
// Returns false if letter has been seen before
110
- public void LogThisLetterAsRead ( )
239
+ public void LogAsRead ( )
111
240
{
112
241
if ( FirstSeenOrder < 0 )
113
242
{
@@ -128,18 +257,50 @@ public void LogThisLetterAsRead()
128
257
public bool DoesRepeat { get ; private set ; }
129
258
}
130
259
131
- public static void ValidateLetter ( int letter )
260
+ private static int FindCurrentFirstNRE ( OrderedLetter [ ] letterTracker )
132
261
{
133
- if ( letter < 'a' || letter > 'z' )
134
- throw new ArgumentException (
135
- "Stream may contain only letters between 'a' and 'z', inclusive." ) ;
136
- }
262
+ var allCurrentNREQuery = letterTracker
263
+ . Where ( ol => ol . FirstSeenOrder >= 0 )
264
+ . Where ( ol => ol . DoesRepeat == false ) ;
137
265
138
- const int NO_NRE = - 1 ;
266
+ // I think Count only does a single traversal to check and count the elements, afaik
267
+ if ( allCurrentNREQuery . Count ( ) == 0 )
268
+ {
269
+ return NO_NRE ;
270
+ }
271
+
272
+
273
+ // I think that this uses lazy evaluation in that OrderBy remains only as a
274
+ // stored instruction until a LINQ "execute" command is added
275
+ // it only needs to walk the array once and find the element
276
+ // that meets the other criteria with the smallest FirstSeenOrder
277
+ // Doesn't need to copy the array or do a full sort, etc.
278
+ var newFirstNRE = allCurrentNREQuery
279
+ . OrderBy ( ol => ol . FirstSeenOrder )
280
+ . First ( ) ;
281
+ // That is, First does the least amount of work necessary to figure
282
+ // out what is the first element of the sequence
283
+
284
+
285
+ // Reverse lookup to figure out what letter the found newFirstNRE
286
+ // corresponds to.
287
+ // An alternative to this approach is for each OrderedLetter to also
288
+ // store what letter it reprents, which seems silly and can fall out
289
+ // of sync. Or we could use use a dictionary instead of an array
290
+ // to store the OrderedLetter objects (which is overkill)
291
+ // Then we could iterate on the kvps and have access to the keys that way.
292
+ for ( var i = 0 ; i < LETTER_COUNT ; ++ i )
293
+ {
294
+ if ( ReferenceEquals ( letterTracker [ i ] , newFirstNRE ) )
295
+ return 'a' + i ;
296
+ }
297
+
298
+ throw new ArgumentException (
299
+ "An element in letterTracker met the query criteria," +
300
+ "but that element isn't in letterTracker? Wat." ) ;
301
+ }
139
302
140
- const int LETTER_COUNT = 'z' - 'a' ;
141
303
142
- // To the result List<int> for each letter in the stream
143
304
public static List < int > PrintFirstNRE ( StreamReader sr )
144
305
{
145
306
if ( sr == null )
@@ -151,7 +312,7 @@ public static List<int> PrintFirstNRE(StreamReader sr)
151
312
// Console.WriteLine(Convert.ToChar(sr.Read()));
152
313
//}
153
314
154
-
315
+
155
316
var letterTracker = new OrderedLetter [ LETTER_COUNT ] ;
156
317
for ( var i = 0 ; i < LETTER_COUNT ; ++ i )
157
318
{
@@ -185,7 +346,7 @@ public static List<int> PrintFirstNRE(StreamReader sr)
185
346
var currLetter = sr . Read ( ) ;
186
347
Console . WriteLine ( $ "Reading '{ Convert . ToChar ( currLetter ) } ' from stream.") ;
187
348
ValidateLetter ( currLetter ) ;
188
- letterTracker [ currLetter - 'a' ] . LogThisLetterAsRead ( ) ;
349
+ letterTracker [ currLetter - 'a' ] . LogAsRead ( ) ;
189
350
190
351
var currFirstNRE = FindCurrentFirstNRE ( letterTracker ) ;
191
352
firstNREList . Add ( currFirstNRE ) ;
@@ -213,49 +374,6 @@ public static List<int> PrintFirstNRE(StreamReader sr)
213
374
return firstNREList ;
214
375
}
215
376
216
- private static int FindCurrentFirstNRE ( OrderedLetter [ ] letterTracker )
217
- {
218
- var allCurrentNREQuery = letterTracker
219
- . Where ( ol => ol . FirstSeenOrder >= 0 )
220
- . Where ( ol => ol . DoesRepeat == false ) ;
221
-
222
- // I think Count only does a single traversal to check and count the elements, afaik
223
- if ( allCurrentNREQuery . Count ( ) == 0 )
224
- {
225
- return NO_NRE ;
226
- }
227
-
228
-
229
- // I think that this uses lazy evaluation in that OrderBy remains only as a
230
- // stored instruction until a LINQ "execute" command is added
231
- // it only needs to walk the array once and find the element
232
- // that meets the other criteria with the smallest FirstSeenOrder
233
- // Doesn't need to copy the array or do a full sort, etc.
234
- var newFirstNRE = allCurrentNREQuery
235
- . OrderBy ( ol => ol . FirstSeenOrder )
236
- . First ( ) ;
237
- // That is, First does the least amount of work necessary to figure
238
- // out what is the first element of the sequence
239
-
240
-
241
- // Reverse lookup to figure out what letter the found newFirstNRE
242
- // corresponds to.
243
- // An alternative to this approach is for each OrderedLetter to also
244
- // store what letter it reprents, which seems silly and can fall out
245
- // of sync. Or we could use use a dictionary instead of an array
246
- // to store the OrderedLetter objects (which is overkill)
247
- // Then we could iterate on the kvps and have access to the keys that way.
248
- for ( var i = 0 ; i < LETTER_COUNT ; ++ i )
249
- {
250
- if ( ReferenceEquals ( letterTracker [ i ] , newFirstNRE ) )
251
- return 'a' + i ;
252
- }
253
-
254
- throw new ArgumentException (
255
- "An element in letterTracker met the query criteria," +
256
- "but that element isn't in letterTracker? Wat." ) ;
257
- }
258
-
259
377
260
378
private class LetterTracker
261
379
{
0 commit comments