Click here to Skip to main content
15,889,281 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I wrote program to solve systems of linear equations
and I want to read data from text file in the format

number of equations
coefficients of row #1 including element of the vector of independent terms
separated by space
coefficients of row #2 including element of the vector of independent terms
separated by space

but i have found how to read file line by line into string so far

C#
using System;
using System.IO;
using System.Globalization;
namespace LUdecomposition
{
	class LUdecomposition
	{
		public const double ZERO = 1.0e-15;
		public static void Main()
		{
			char esc;
			string str,path;
			int i,j,n;
			double[,] A;
			double[] b;
			int[] p;
			double d;
			NumberFormatInfo nfi = new NumberFormatInfo();
			nfi.NumberDecimalSeparator = ".";
			Console.WriteLine("Podaj ścieżkę do pliku w którym chcesz zapisać wynik");
			path = Console.ReadLine();
			using(StreamWriter sw = new StreamWriter(path,true))
			{
				do
				{
					try
					{
						Console.Clear();
						Console.WriteLine("Rozwiązywanie układów równań liniowych metodą rozkładu macierzy LU = PA");
						Console.WriteLine();
						Console.WriteLine("Podaj liczbę równań n=");
						str = Console.ReadLine();
						int.TryParse(str,out n);
						A = new double[n,n];
						b = new double[n];
						p = new int[n];
						for(i = 0;i < n;i++)
						{
							Console.WriteLine("Wprowadz " + (i+1).ToString(nfi) + ". wiersz macierzy");
							for(j = 0;j < n;j++)
							{
								str = Console.ReadLine();
								double.TryParse(str,out A[i,j]);
							}
							Console.WriteLine("Wprowadz " + (i+1).ToString(nfi) + ". wyraz wolny");
							str = Console.ReadLine();
							double.TryParse(str,out b[i]);
						}
						FactorLU(n,A,p,out d);
						sw.WriteLine(d.ToString(nfi));
						for(i = 0;i < n && Math.Abs(d) > ZERO  ;i++)
						{
							for(j = 0;j < n; j++)
							{
								Console.Write(A[i,j].ToString(nfi)+" , ");
								sw.Write(A[i,j].ToString(nfi) + " , ");
							}
							Console.WriteLine();
							sw.WriteLine();
						}
						if(Math.Abs(d) > ZERO)
						{
							SolveLU(n,A,p,b);
							for(i = 0;i < n && Math.Abs(d) > ZERO ;i++)
							{
								Console.WriteLine(b[i].ToString(nfi));
								sw.WriteLine(b[i].ToString(nfi));
							}
							Console.WriteLine();
							sw.WriteLine();
						}
					}
					catch(System.IndexOutOfRangeException e)
					{
						
					}
					esc = (char)Console.ReadKey().Key;
				}
				while(esc != (char)ConsoleKey.Escape);
			}
		}
		public static void FactorLU(int n,double[,] A,int[] p,out double d)
		{
			int k,i,j,l;
			double pmax,tmp;
			d = 1.0;
			for(k = 0;k < n ;k++)
			{
				pmax = Math.Abs(A[k,k]);
				l = k;
				for(j = k + 1;j < n; j++)
				{
					if(Math.Abs(A[j,k]) > pmax)
					{
						pmax = Math.Abs(A[j,k]);
						l = j;
					}
				}
				if(l != k)
				{
					for(j = 0;j < n; j++)
					{
						tmp = A[k,j];
						A[k,j] = A[l,j];
						A[l,j] = tmp;
					}
					d = -d;
				}
				d *= A[k,k];
				if(pmax <= ZERO)
					return ;	
				p[k] = l;
				for(i = k + 1; i < n; i++)
				{
					A[i,k]/=A[k,k];
					for(j = k + 1;j < n; j++)
						A[i,j] -= A[i,k]*A[k,j];
				}
			}
		}
		public static void SolveLU(int n,double[,] LU,int[] p,double[] b)
		{
			int i,k;
			double tmp;
			for(k = 0;k < n - 1; k++)
			{
				tmp = b[k];
				b[k] = b[p[k]];
				b[p[k]] = tmp;
			}
			for(k = 1;k < n; k++)
				for(i = 0; i < k; i++)
					b[k] -= b[i]*LU[k,i];
			for(k = n - 1; k >= 0; k--)
			{
				for(i = k + 1;i < n; i++)
					b[k] -= LU[k,i]*b[i];
				b[k] /= LU[k,k];
			}
		}
	}
}


What I have tried:

I found how to read file line by line into string


C#
using System;
using System.IO;
namespace FileApplication {
   class Program {
       static void Main(string[] args) {
           try{
              // Create an instance of StreamReader to read from a file.
              // The using statement also closes the StreamReader.
           string path;
           Console.ReadLine(path);
           using(StreamReader sr =newStreamReader(path)) {
              string line;

              // Read and display lines from the file until 
              // the end of the file is reached. 
             while((line = sr.ReadLine())!=null) {
               Console.WriteLine(line);
          }
        }
      }catch(Exception e) {
       // Let the user know what went wrong.
      Console.WriteLine("The file could not be read:");
      Console.WriteLine(e.Message);
    }
   Console.ReadKey();
 }
}
}


I dont want to use Split function to parse data from string
because it needs to create extra string array

Maybe Trim, IndexOf,Substring will be enough
but how use them
Posted
Updated 21-Jan-20 5:00am

Quote:
I dont want to use Split function to parse data from string

You claim to have space-separated data, so why make it so difficult for yourself? Split is absolutely the easiest tool for this job. If you insist on not using it, you can iterate over all characters of your text file and act differently on numbers, spaces, etc. (such as, keep track of the digits until you come across a new space) but I really don't see the point in that over using Split.
 
Share this answer
 
Comments
Member 14318223 19-Jan-20 15:19pm    
You didn't quote the whole sentence
I saw parsing multiple numbers from string using Split
but i dont want to use extra string array and that's why i look for other solution
Split is space ineffective solution
Pascal has pos and copy , here C# should have similar functions
All string manipulation functions create new strings - they have to because strings are immutable; they cannot be changed at all once they are created.

So use string.Split - it'll make your code much clearer and probably easier to read.
In addition, I'd read the file like this:
C#
string[] lines = File.ReadAllLines(path);
foreach (string line in lines)
   {
   string[] parts = line.Split(" ");
   ...
   }
 
Share this answer
 
If you want to avoid allocating new strings and string arrays, you can cobble something together using the relatively new ReadOnlySpan<T> type.

C# - All About Span: Exploring a New .NET Mainstay | Microsoft Docs[^]

There doesn't seem to be any built-in support for splitting strings yet, but it's fairly easy to roll your own:
C#
public static class StringExtensions
{
    public ref struct SplitByCharEnumerator
    {
        private ReadOnlySpan<char> _value;
        private readonly ReadOnlySpan<char> _separator;
        private readonly bool _isEmpty;
        private bool _removeEmpty;
    
        public SplitByCharEnumerator(ReadOnlySpan<char> value, ReadOnlySpan<char> separator, StringSplitOptions options)
        {
            _value = value;
            _separator = separator;
            _removeEmpty = options == StringSplitOptions.RemoveEmptyEntries;
            _isEmpty = _value.IsEmpty || _separator.IsEmpty;
            Current = default;
        }
    
        public SplitByCharEnumerator GetEnumerator() => this;
    
        public bool MoveNext()
        {
            if (_isEmpty)
            {
                if (_removeEmpty) return false;
    
                _removeEmpty = true;
                Current = _value;
                return true;
            }
    
            while (!_value.IsEmpty)
            {
                int index = _value.IndexOfAny(_separator);
                if (index == -1)
                {
                    Current = _value;
                    _value = default;
                    return true;
                }
    
                if (index != 0 || !_removeEmpty)
                {
                    Current = _value.Slice(0, index);
                    _value = _value.Slice(index + 1);
                    return true;
                }
    
                _value = _value.Slice(index + 1);
            }
    
            return false;
        }
    
        public ReadOnlySpan<char> Current { get; private set; }
    }
    
    public static SplitByCharEnumerator Split(this ReadOnlySpan<char> source, char[] separator, StringSplitOptions options) => new SplitByCharEnumerator(source, separator, options);
    
    public static SplitByCharEnumerator Split(this ReadOnlySpan<char> source, params char[] separator) => new SplitByCharEnumerator(source, separator, StringSplitOptions.None);
}
The only complicated part is that the iterator has to be a ref struct[^], so it can't implement IEnumerable<T>. But you can still use it in a foreach loop:
C#
foreach (string line in File.ReadLines(path))
{
    foreach (ReadOnlySpan<char> part in line.AsSpan().Split(' '))
    {
        ...
    }
}
Unfortunately, .NET Framework doesn't seem to have any way to parse a number from a ReadOnlySpan<char> without converting it to a string first; .NET Core 2.2 or later will let you parse directly without any extra allocations.
 
Share this answer
 
Comments
Member 14318223 22-Jan-20 21:19pm    
I thought about using Trim,IndexOf,Substring and TryParse functions
but then we should check if all expected data are read successfully
I thought about functions like Pos , Copy in Pascal
but if your solution has better space complexity maybe I should consider it

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900