Skip to content

Commit f2fc4f4

Browse files
committed
Update - Removed double lookup on dictionaries.
1 parent e8e9421 commit f2fc4f4

File tree

2 files changed

+97
-6
lines changed

2 files changed

+97
-6
lines changed

entries/ikelaiah/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,10 @@ Iwan Kelaiah
127127
* Converting Float as String to Int was a bit slow, so resorted to a lookup instead. This saves 30-45 seconds.
128128
* Re-arranged `if` statements in two places. This saves 10-15 seconds x 2 = ~ 30 seconds saving.
129129

130+
* 1.8
131+
* Revision release - Sequential approach. 4-6 mins on my Inspiron 15 7510 laptop (a little improvement on speed).
132+
* Removed double lookup on dictionaries.
133+
130134
## License
131135

132136
This project is licensed under the MIT License - see the LICENSE.md file for details

entries/ikelaiah/src/weatherstation.pas

Lines changed: 93 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ TWeatherStation = class
5252
lookupStrFloatToIntList: TValidTemperatureDictionary;
5353
procedure CreateLookupTemp;
5454
procedure ReadMeasurements;
55+
procedure ReadMeasurementsBuf;
5556
procedure ParseStationAndTemp(const line: string);
5657
procedure AddCityTemperatureLG(const cityName: string; const newTemp: int64);
5758
procedure SortWeatherStationAndStats;
@@ -239,10 +240,10 @@ procedure TWeatherStation.AddCityTemperatureLG(const cityName: string;
239240
stat: PStat;
240241
begin
241242
// If city name esxists, modify temp as needed
242-
if self.weatherDictionary.Contains(cityName) then
243+
if self.weatherDictionary.TryGetValue(cityName, stat) then
243244
begin
244245
// Get the temp record
245-
stat := self.weatherDictionary[cityName];
246+
// stat := self.weatherDictionary[cityName];
246247

247248
// Update min and max temps if needed
248249
// Re-arranged the if statement, to achieve minimal if checks.
@@ -309,11 +310,9 @@ procedure TWeatherStation.ParseStationAndTemp(const line: string);
309310
strFloatTemp := Copy(line, delimiterPos + 1, Length(line));
310311

311312
// Using a lookup value speeds up 30-45 seconds
312-
if self.lookupStrFloatToIntList.Contains(strFloatTemp) then
313+
if self.lookupStrFloatToIntList.TryGetValue(strFloatTemp, parsedTemp) then
313314
begin
314-
parsedTemp := self.lookupStrFloatToIntList[strFloatTemp];
315-
self.AddCityTemperatureLG(Copy(line, 1, delimiterPos - 1),
316-
parsedTemp);
315+
self.AddCityTemperatureLG(Copy(line, 1, delimiterPos - 1), parsedTemp);
317316
end;
318317
end;
319318
end;
@@ -346,11 +345,99 @@ procedure TWeatherStation.ReadMeasurements;
346345
end;
347346
end;
348347

348+
procedure TWeatherStation.ReadMeasurementsBuf;
349+
var
350+
fileStream: TFileStream;
351+
memStream: TMemoryStream;
352+
streamReader: TStreamReader;
353+
buffer: TBytes;
354+
bytesRead, totalBytesRead, chunkSize, lineBreakPos, chunkIndex,
355+
index, lineCount: int64;
356+
begin
357+
358+
chunksize := 536870912 * 1;
359+
360+
// Open the file for reading
361+
fileStream := TFileStream.Create(self.fname, fmOpenRead);
362+
SetLength(buffer, chunkSize);
363+
try
364+
memStream := TMemoryStream.Create;
365+
try
366+
totalBytesRead := 0;
367+
chunkIndex := 0;
368+
lineCount := 0;
369+
370+
// Read and parse chunks of data until EOF
371+
while totalBytesRead < fileStream.Size do
372+
begin
373+
// Read more bytes and keep track on bytes read
374+
bytesRead := fileStream.Read(buffer[0], chunkSize);
375+
Inc(totalBytesRead, bytesRead);
376+
377+
// Find the position of the last newline character in the chunk
378+
lineBreakPos := BytesRead;
379+
while (lineBreakPos > 0) and (Buffer[lineBreakPos - 1] <> Ord(#10)) do
380+
Dec(lineBreakPos);
381+
382+
{ Now, must ensure that if the last byte read in the current chunk
383+
is not a newline character, the file pointer is moved back to include
384+
that byte and any preceding bytes of the partial line in the next
385+
chunk's read operation.
386+
387+
Also, no need to update the BytesRead variable in this context because
388+
it represents the actual number of bytes read from the file, including
389+
any partial line that may have been included due to moving the file
390+
pointer back.
391+
Ref: https://www.freepascal.org/docs-html/rtl/classes/tstream.seek.html}
392+
if lineBreakPos < bytesRead then
393+
fileStream.Seek(-(bytesRead - lineBreakPos), soCurrent);
394+
//{$IFDEF DEBUG}
395+
// Do something with the chunk here
396+
// Like counting line
397+
for index := 0 to lineBreakPos - 1 do
398+
if buffer[index] = Ord(#10) then
399+
lineCount := lineCount + 1;
400+
//{$ENDIF DEBUG}
401+
402+
// Use memory stream & stream reader
403+
memStream.Write(buffer[0], lineBreakPos - 1);
404+
memStream.Position:=0;
405+
streamReader := TStreamReader.Create(memStream);
406+
try
407+
while not streamReader.EOF do
408+
begin
409+
// WriteLn(streamReader.ReadLine);
410+
self.ParseStationAndTemp(streamReader.ReadLine);
411+
end;
412+
finally
413+
streamReader.Free;
414+
end;
415+
//{$IFDEF DEBUG}
416+
// Display user feedback
417+
WriteLn('Line count: ', IntToStr(lineCount));
418+
WriteLn('Chunk ', chunkIndex, ', Total bytes read:', IntToStr(totalBytesRead));
419+
//{$ENDIF DEBUG}
420+
421+
//{$IFDEF DEBUG}
422+
// Increase chunk index - a counter
423+
Inc(chunkIndex);
424+
//{$ENDIF DEBUG}
425+
end;
426+
finally
427+
memStream.Free;
428+
end;
429+
finally
430+
// Close the file
431+
fileStream.Free;
432+
end;
433+
end;
434+
349435
// The main algorithm
350436
procedure TWeatherStation.ProcessMeasurements;
351437
begin
352438
self.CreateLookupTemp;
353439
self.ReadMeasurements;
440+
//self.ReadMeasurementsBuf;
354441
self.SortWeatherStationAndStats;
355442
self.PrintSortedWeatherStationAndStats;
356443
end;

0 commit comments

Comments
 (0)