Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# reading .txt File FORMATTED

Tags:

c#

file-io

I have a specific Textfile:

197 17.16391215
198 17.33448519
199 17.52637986
200 17.71827453
201 17.9101692
202 18.10206387
203 18.29395854
204 18.48585321
205 18.67774788
206 18.86964255
207 19.06153722

and so on. To be clear: First column (197,198,..) indicates a framenumber and the second column (17.xxx,...) indicates a position linked to the framenumber, and vice-versa.
Now I want to separate each Line in different Arrays. With

string[] delimiters = new string[] {" ", "\r\n" };
string line = reader.ReadToEnd();
string[] test = line.Split(delimiters, StringSplitOptions.None);

I got one Array with all the entries from the Textfile. But I want all framenumbers (first column) in one Array and in another second Array all positions.

My job I have to do is as follow: I will get a position number (e.g. 18.10) then I have to search in the .txt file in the second column for the nearest matching number and return the linked framenumber (in this case 202). My idea was to generate two matching arrays, search in one for the position and returning from the other for the framenumber. As I searched half a day on the internet I found many things like all the .select stuff, but not anything matching directly do my problem; but maybe I am to dumb at the moment.

So thanks for any help. Hopefully you can understand my English :P

like image 725
Patrick Avatar asked Dec 27 '22 05:12

Patrick


1 Answers

EDIT 2 following your comment, that you wish to repeat the search 24 times a second.

First, let me caveat, if you are trying to play a stream of frames then looking up a list is the wrong approach. The right approach is beyond the scope of the question but, essentially you want to throttle the display of sequential data.

On the assumption that the values do not change, and your lookups are random, not sequential. You could try some code like this.

private readonly List<int> ids = new List<int>();
private readonly IList<double> values = new List<double>();

public void LoadData(string path)
{
    foreach (var line in File.ReadLines(path))
    {
        var pair = line.Split(' ');
        this.ids.Add(int.Parse(pair[0]));
        this.values.Add(double.Parse(pair[1]));
    }
}

public double Lookup(int id)
{
    return this.values[this.ids.FindIndex(i => i >= id)];
}

If more performance is required you could use the specialized binary search here.

EDIT after reading and hopefully, understanding

and assuming the frames are in ascending Id order.

double GetFrameValue(string path, int limit)
{
    string [] parts;
    foreach (var line in File.ReadLines(path))
    {
       parts = line.Split(' '); 
       var frameId = int.Parse[0];
       if (frameId >= limit)
       {
           break;
       }
    }

    return double.Parse(parts[1]);
}

This has the distinct advantage of only reading the file as far as necessary and not holding it all in memory. If you are going to read the file repeatedley at random frame positions then you'd be better off loading it all into some Collection with fast comparison performance, unless the file is very large.


How about,

IEnumerable<KeyValuePair<int, double>> ReadFrames(string path)
{
    foreach (var line in File.ReadLines(path))
    {
       var parts = line.Split(' '); 
       yield return new KeyValuePair<int, double>(
           int.Parse(parts[0]),
           double.Parse(parts[1]));
    }
}

var frames = new Dictionary<int, double>(ReadFrames("yourfile.txt"));

var frameIds = frames.Keys;
var values = frames.Values;

as stated in comments,

var frames = File.ReadLines("yourfile.txt")
    .Select(line => line.Split(' '))
    .ToDictionary(pair => int.Parse(pair[0]), pair => double.Parse(pair[1])); 

var frameIds = frames.Keys;
var values = frames.Values;

should work just as well.

like image 80
Jodrell Avatar answered Jan 12 '23 04:01

Jodrell