Przesyłanie tablic wielowymiarowych między Formami

0

Witam
Mam kilka Formsów i tak:
Form1 - głowna
Losuj - generują tablice dwuwymiarowe i wypełniająca je losowymi wartościami
Klasyfikuj - wykonuje obliczenia na tablicach stworzonych w Losuj

Problem:
pomiędzy formami można w miarę łatwo przesyłać tekst lub pojedyncze zmienne co jednak gdy mamy tablice i to wielowymiarową?

Form1

 private void buttonLosujTRN_Click(object sender, EventArgs e)
        {
            
            Losuj f2 = new Losuj(this);
            f2.ShowDialog();
        }

Losuj:

public partial class Losuj : Form
    {
        Form1 f1;
        
        public Losuj(Form1 f1)
        {
            
            this.f1 = f1;
            InitializeComponent();
        } 

W ten sposób mogę łatwo odnieść się do wszystkich publicznych elementów na Form1 i np. gdy z formy Losuj chce przesłać do Form1 jakiś string to mogę zrobić to tak:

 f1.stringTEST = stringtabTRN;

Pytania:

  1. Czy powyższy przykład skopiuje stringtabTRN do stringTEST czy utworzy "wskaźnik" w stringTEST na obiekt stringtabTRN?
  2. Jak przesłać tablice wymiarową? ja mam dwa pomysły ale żaden mi nie odpowiada:
    a) zrobić pętle pod każdy wymiar i po kolei przesyłać tab[i,j]
    b) zapisać tablice do stringu i potem odczytać string do tablicy na Form1

Żaden z powyższych przykładów nie podoba mi się, wolałbym po prostu móc jakoś bezpośrednio odwoływać się do elementów utworzonych na formie Losuj.

0
wierzbiks napisał(a)
  1. Czy powyższy przykład skopiuje stringtabTRN do stringTEST czy utworzy "wskaźnik" w stringTEST na obiekt stringtabTRN?

Refwrencję nie wskaźnik jeśli już. Ale odp. jest NIE. string mimo że jset klasą to jest tzn. type immutable (niezmiennym). Więc każda operacja modyfikująca obiekt typu string powoduje utworzenie nowej instancji.

wierzbiks napisał(a)
  1. Jak przesłać tablice wymiarową? ja mam dwa pomysły ale żaden mi nie odpowiada:

Także możesz przez pola, a lepiej właściwości publiczne. Akurat tutaj będziesz przekazywał referencje.

wierzbiks napisał(a)

a) zrobić pętle pod każdy wymiar i po kolei przesyłać tab[i,j]

nie ma potrzeby, patrz wyżej

wierzbiks napisał(a)

b) zapisać tablice do stringu i potem odczytać string do tablicy na Form1

grrrr, w życiu! bo znajdę i będę bił

Poza tym nie wiem po co ci tyle form, których nazwy wskazują na wykonywanie operacji będących domeną logiki, a nie wyświetlania.
Powinieneś stworzyć pewną klasę która będzie enkapsulowała (wiem trudne słowo ;]) wszelkie operacje logiczne, tzn. trzymała dane (tablicę), wykonywała losowania etc. Obiekt takiej klasy powinien był przekazywany między oknami, a nie referencje do okien (akurat w tym przypadku nie widzę takiej potrzeby). W ten sposób odseparujesz logikę od warstwy prezentacji.

0
massther napisał(a)

Poza tym nie wiem po co ci tyle form, których nazwy wskazują na wykonywanie operacji będących domeną logiki, a nie wyświetlania.
Powinieneś stworzyć pewną klasę która będzie enkapsulowała (wiem trudne słowo ;]) wszelkie operacje logiczne, tzn. trzymała dane (tablicę), wykonywała losowania etc. Obiekt takiej klasy powinien był przekazywany między oknami, a nie referencje do okien (akurat w tym przypadku nie widzę takiej potrzeby). W ten sposób odseparujesz logikę od warstwy prezentacji.

Ale ja właśnie mam stworzoną taką klase:

    public class Macierz
    {
        public double[,] tab;
        public int w;
        public int k;

        public Macierz(int wiersz, int kolumna)
        {
            this.w = wiersz;
            this.k = kolumna;
            this.tab = new double[w, k];
        }

        public void losuj()
        {
            Random liczba = new Random();
            Random klasa = new Random();

            for (int i = 0; i < w; i++)
            {
                for (int j = 0; j < k; j++)
                {
                    this.tab[i, j] = liczba.Next(0, 10);
                    if (j == k - 1) this.tab[i, j] = klasa.Next(0, 2);
                }

            }
        }

    } 

Tylko że to działa tak:
Na Form1 mogę wybrać losowanie tablicy (wtedy otwieram forme Losuj i tam podaje wielkość kolumn wierszy itp. i klikam generuj) lub wczytać z pliku.
I teraz jak na formie Losuj utworze obiekt klasy Macierz to jak do tego utworzonego obiektu odwoływać się na formie głównej Form1?

0

Co robi Form1? Ja zdefiniowałbym obiekt typu Macierz w Form1.
Chcesz losować nową, to otwierasz LosujForm gdzie podajesz jej wielkość, przycisk generuj zamyka formę losujForm z DialogResult.OK i przez publiczne właściwości (tylko get) zwraca liczbę wierszy i kolumn. Form1 zbiera wielkość, tworzy nowy obiekt Macierz i wywołuje losuj().

class LosujForm : Form
{
public int MatrixRows {get {return (int)numericUpDownRows.Value;}}
public int MatrixCols {get {return (int)numericUpDownCols.Value;}}
}

w form1:
void showLosujForm_Click(...)
{
LosujForm losuj = new LosujForm();
if (losuj.DialogResult == DialogResult.OK)
{
this.matrix = new Macierz(losuj.Rows, losuj.Cols);
this.matrix.Losuj();
}
}

Czyli LosujForm zajmuje się tylko pobraniem informacji od usera o rozmiarze, nie zawiera żadnej logiki.

Na marginesie: nazwy metod wielkimi literami, styl Pascal.
public double[,] tab;
public int w;
public int k;
czyli umożliwiasz zmianę wielkości a nawet tablicy przechowującej macierz. Generalnie ktoś kto dostanie taką klasę może sobie zrobić kuku.
Te pola powinny być prywatne. Publiczne właściwości powinny tylko zwracać (get) rozmiar, bo ich zmiana wiąże się ze zmianą tablicy.
Tablica do modyfikacji powinna być udostępniona przez indexer na Macierz.

public double this[int row, int col]
{
get{return this.tab[row,col];}
set{this.tab[row,col] = value;}
}
Oczywiście walidacja czy ktoś nie chce wyjechać za tablicę można dodać , chociaż sama array rzuci IndexOutOfRange jeśli coś będzie nie tak.

0

zaraz popróbuje z tymi właściwościami tylko przeczytam najpierw jakiś tutorial bo jeszcze nie używałem właściwości.
W między czasie jednak sam sobie poradziłem

Form1:

 
public Macierz trn;
public Macierz tst;

        private void buttonLosujTRN_Click(object sender, EventArgs e)
        {
            
            Losuj f2 = new Losuj(this);
            f2.ShowDialog();
        }

          //wyświetlanie  macierzy jeśli wyhenerowana została na formie Losuj (w innym wypadku przycisk wogóle nie powoduje żadnej reakcji)
         private void buttonpokaz_Click(object sender, EventArgs e)
        {
                   
            string tabTRN = "";

            for (int i = 0; i < w1; i++)
            {
                for (int j = 0; j < k; j++)
                {
                    tabTRN += (trn.tab[i, j].ToString() + " ");
                }
                tabTRN += Environment.NewLine;
                
            }

            textBoxPokaz.Text = (tabTRN);
        }

Forma Losuj:

 
    public partial class Losuj : Form
    {
        Form1 f1;
        
        public Losuj(Form1 f1)
        {
            
            this.f1 = f1;
            InitializeComponent();
        }


        private void buttonGeneruj_Click(object sender, EventArgs e)
        {
            
            string kolumna = textBoxKolumny.Text;
            string wierszTrn = textBoxWierszTRN.Text;
            string wierszTsn = textBoxWierszTST.Text;

            f1.k = int.Parse(kolumna);
            f1.w1 = int.Parse(wierszTrn);
            f1.w2 = int.Parse(wierszTsn);
            
            f1.trn = new Macierz(f1.w1, f1.k);
            f1.trn.losuj();
            
           //wyświetla aktualnie wykenerowaną tablice:
            string tabTRN = "";

            for (int i = 0; i < f1.w1; i++)
            {
                for (int j = 0; j < f1.k; j++)
                {
                    tabTRN += (f1.trn.tab[i, j].ToString() + " ");
                }
                tabTRN += Environment.NewLine;

            }

            textBoxTRN.Text = (tabTRN);

        }

    }

Nie zamieszczałem całego kodu tylko przykłady z tworzeniem jednej macierzy.

Ten sposób działa i jest całkiem fajny pytanie czy to dobry sposób i czy mogę go używać czy raczej powinienem stosować właściwości?

0

Po co powtarza kod powodujący wyświetlanie macierzy. Wydziel go do osobnej metody, która przyjmie macierz a zwróci string
string MacierzJakoTekst(Macierz m)

textBoxTRN.Text = MacierzJakoTekst(f1.trn);

Ryzykujesz exceptionem podczas parsowania
string wierszTsn = textBoxWierszTST.Text;
f1.k = int.Parse(kolumna);
Albo użyj TryParse, albo lepiej, zamianst kontrolki textbox użyj NumericUpDown

0

ten kod klepałem na szybko i te powtarzanie jest po to żeby zobaczyć że ten sposób rzeczywiście działa.
exceptionem będę zajmowałem się później na razie chciałem po prostu sprawdzić jak operować na 1 obiekcie z kilku form no i powtarzam pytanie czy mój powyższy sposób jest dobry czy raczej powinienem zamienić to na właściwości o których wcześniej wspomniałeś?

0

Przetwarzanie stringów w pętli jest niewydajne. Powinno się używać klasy StringBuilder.

0

klasa tworząca macierze:

    public class Macierz
    {
        public double[,] tab;
        public int w;
        public int k;
        Random liczba = new Random();
        Random klasa = new Random();

        public Macierz(int wiersz, int kolumna)
        {
            this.w = wiersz;
            this.k = kolumna;
            this.tab = new double[w, k];
        }

        public void losuj()
        {
            

            for (int i = 0; i < w; i++)
            {
                for (int j = 0; j < k; j++)
                {
                    this.tab[i, j] = liczba.Next(0, 10);
                    if (j == k - 1) this.tab[i, j] = klasa.Next(0, 2);
                }

            }
        }


        public string wyswietl()
        {
            string tablica = "";

            
            for (int i = 0; i < w; i++)
            {
                for (int j = 0; j < k; j++)
                {
                    tablica += (this.tab[i, j].ToString() + " ");
                }
                tablica += Environment.NewLine;
            }
            return tablica;
        }

    } 

Form1:

        public int k;
        public int w1;
        public int w2;
        public Macierz trn;
        public Macierz tst;

        public Form1()
        {
            InitializeComponent();
        }

        private void buttonLosuj_Click(object sender, EventArgs e)
        {
            Losuj f2 = new Losuj(this);
            f2.ShowDialog();
        }
        
//Ten element jest nie potrzebny pokazuje tylko ze jesli uzyjemy formy Losuj to wyniki będa dostepne na Form1
        private void buttonPokaz_Click(object sender, EventArgs e)
        {
            textBoxPokaz.Text = (tst.wyswietl());
        }
 

Forma Losuj:

 
    public partial class Losuj : Form
    {
        Form1 f1;
        public Losuj(Form1 f1)
        {
            this.f1 = f1;
            InitializeComponent();
        }


        private void buttonGeneruj_Click(object sender, EventArgs e)
        {

            f1.k = (int)numericKolumny.Value;
            f1.w1 = (int)numericWierszTRN.Value;
            f1.w2 = (int)numericWierszTST.Value;

            f1.trn = new Macierz(f1.w1, f1.k);
            f1.trn.losuj();
            
            f1.tst = new Macierz(f1.w2, f1.k);
            f1.tst.losuj();
            f1.tst.losuj();  //UWAGA: dlaczego jeśli jest tylko jedna taka linijka to wyniki sa takie same jak w f1.trn.losuj(); ??

            textBoxTRN.Text = (f1.trn.wyswietl());
            textBoxTST.Text = (f1.tst.wyswietl());

        }

Na formie Losuj muszą być wyświetlane wyniki losowania żeby użytkownik widział jakie macierze zostały wylosowane.
Więc jak zrobić właściwość to tych tablic bo mi wydaje się że nie ma sensu tworzyć każdej właściwości dla:

         public int k;
        public int w1;
        public int w2;
        public Macierz trn;
        public Macierz tst;

Ponadto w Form1 będą wykonywane obliczenia na tych macierzach stworzonych w formie Losuj + dojdzie kolejna forma umożliwiająca wczytywanie macierzy z pliku.

1

Ja mam jednak wrażenie że jak grochem o ścianę.
Napiszę kawałek gotowca, co by inni potomni coś skumali.

public class Macierz
{
        private double[,] tab; // pola prywatne !!!
        private int rows, cols;

        Random rand = new Random((int)DateTime.Now.Ticks);

        public int Rows {get {return rows;}}
        public int Cols {get {return cols;}}
        public double this[int rowIndex, int colIndex]
        {
            get{return tab[rowIndex, colIndex];}
            set{tab[rowIndex, colIndex] = value;}
        }
 
        public Macierz(int rows, int cols)
        {
            this.rows = cols;
            this.cols = cols;
            this.tab = new double[rows, cols];
        }
 
        public void Losuj() //metody z dużej litery
        {
            for (int i = 0; i < rows; i++)
            {
                for (int j = 0; j < cols; j++)
                {
                    this.tab[i, j] = rand.Next(0, 10);
                    if (j == cols - 1) this.tab[i, j] = rand.Next(0, 2);
                }
             }
        }
 
 
        public string Wyswietl() // nazwy metod dużymi literami!!!
        {
            StringBuilder sb = new StringBuilder();
 
             for (int i = 0; i < rows; i++)
             {
                for (int j = 0; j < cols; j++)
                {
                    sb.Append(this.tab[i, j]).Append(" ");
                }
                sb.AppendLine();
            }
            return sb.ToString();
        }
    } 

/*********************/
private void buttonLosuj_Click(object sender, EventArgs e)
        {
            Losuj f2 = new Losuj(this);
            if (f2.ShowDialog() == DialogResult.OK)
            {
               trn = new Macierz(f2.TRNRows, f2.Cols);
               tst = new Macierz(f2.TSTRows, f2.Cols);
               trn.Losuj();
               tst.Losuj();
               // możesz teraz je gdzieś wyświetlić
            }
        }

WAGA: dlaczego jeśli jest tylko jedna taka linijka to wyniki sa takie same jak w f1.trn.losuj

Bo trzeba doczytać sobie o klasie Random.

Nie wiem po co ci w1, w2, k. A tym bardziej po co są publiczne (tzn. w twoim przypadku żeby w formie losuj odwołać się do nich).

dojdzie kolejna forma umożliwiająca wczytywanie macierzy z pliku.

Tiaaaa, standardowy dialog otwarcia pliku (tak jest taki w .net), a później obsługa czytania pliku w form1, nie wiem po co ci kolejna forma do tego.

0
massther napisał(a)

Nie wiem po co ci w1, w2, k. A tym bardziej po co są publiczne (tzn. w twoim przypadku żeby w formie losuj odwołać się do nich).

Te zmienne są po to że użytkownik może wylosować macierz lub może ją wczytać i w każdym wypadku potrzebne są te same zmienne bo kolumny muszą mieć ten sam rozmiar, różnić się może tylko liczba wierszy (w1,w2). Ponadto wszystkie te wartości (trn,tst,w1,w2,k) będą potem potrzebne do wywoływania funkcji z operacjami na tych macierzach)
np. po wczytaniu już macierzy zaczynamy pierwszą operacje: Metody.Euklides(trn,tab,w1,w2,k).

Tak wygląda forma losuj - użytkownik konfiguruje i losuje sobie macierze.
user image
http://img862.imageshack.us/i/84730931.jpg

i dlatego wydaję mi się że moja wersja z przekazaniem wszystkich wartości do formy Losuj jest w tym wypadku lepsza.

0

No i nie masz racji, bo nie rozumiesz programowania obiektowego. Po to napisałeś klasę macierz i po to zawiera ona pola liczba wierszy/kolumn żeby ich używać. w1, w2, k potrzebne są ci tylko chwilowo do utworzenia macierzy, a nawet i takie zmienne lokalne nie są potrzebne, bo można od razu do konstruktora przekazać wartości z pola NumericUpDown. Porządna klasa będzie miała walidację czy l. wierszy/kolumn jest większa od zera i rzuci odpowiedni wyjątek jeśli nie jest.
Nadal nie rozumiesz co znaczy rozdział logiki od prezentacji i usilnie do formy losuj przekazujesz referencję do form1, a wystarczy żeby losuj zwrotnie oddało wyniki swojej pracy, czyli zebrane wymiary, ewentualnie nowe macierze.
Możesz to zrobić po swojemu, ale ja chciałem pokazać ci jak się to robi profesjonalnie.

0

to jest mój pierwszy program w C# i do tego "okienkowy", przedtem pisałem tylko w c++ i do tego 90% były to programy nie zorientowane obiektowo.

1)więc mam prośbę napisałeś jak powinna wyglądać klasa tworząca macierz i przycisk tworzący ją, czy mógłbyś do tego przerobić/dołączyć
jak powinna wyglądać forma Losuj?

bo z tego co zrozumiałem to na tej formie chcesz żeby podawało się tylko rozmiary nowych macierzy, a losowanie i tworzenie ich przebiegało na głównej formie Form1.

  1. do czego jest poniższa metoda? :
    <quote=massther>J
public class Macierz
{
        private double[,] tab; 
        private int rows, cols;

        public int Rows {get {return rows;}}
        public int Cols {get {return cols;}}
/////////////////////////////////////////////////////////////        
public double this[int rowIndex, int colIndex]   //co dzieje się w tym miejscu?
        {
            get{return tab[rowIndex, colIndex];}
            set{tab[rowIndex, colIndex] = value;}
        }
//////////////////////////////////////////////////////////////////////// 
        public Macierz(int rows, int cols)
        {
            this.rows = cols;
            this.cols = cols;
            this.tab = new double[rows, cols];
        }
   }     
1

tak powinna wyglądać obsługa pokazania formy losuj na formie1

private void buttonLosuj_Click(object sender, EventArgs e)
        {
            Losuj f2 = new Losuj();
            if (f2.ShowDialog() == DialogResult.OK)
            {
               trn = new Macierz(f2.TRNRows, f2.Cols);
               tst = new Macierz(f2.TSTRows, f2.Cols);
               trn.Losuj();
               tst.Losuj();
               // możesz teraz je gdzieś wyświetlić
            }
        }

//w LosujForm
public int TRNRows {get{return (int)numericUpDownTRNRows.Value;}}
// ... etc.

Metoda o którą pytasz w klasie Macierz to tzw. indekser.
Użycie:

Macierz m = new Macierz(4, 6);
m[0,0] = 4; // wartość elementy r=0, c=0 ustawiamy na 4
Debug.Write(m[2,4]); // wypisuje wartość elem. r=2, c=4
m[8,2] = 17;//rzuca błędem, bo nasz macierz jest 4x6, a tu próbujesz wyjechać poza tablicę
0

Wydaje mi się że tłumaczysz metode:

massther napisał(a)

J

        public Macierz(int rows, int cols)
        {
            this.rows = cols;
            this.cols = cols;
            this.tab = new double[rows, cols];
        }

A mi chodzi o to co dzieje się tutaj:

massther napisał(a)

J

public double this[int rowIndex, int colIndex]  
        {
            get{return tab[rowIndex, colIndex];}
            set{tab[rowIndex, colIndex] = value;}
        }  

a nie teraz porównałem te dwie metody i jednak już chyba rozumiem, ten indekser: "public double this[int rowIndex, int colIndex] " służy do podawania wartości danej "komórki" tak?

0

Dobra poprzerabiałem program wg twoich porad tak że po kliknięciu przycisku Generuj otwiera się forma Losuj gdzie podaje się tylko wymiary macierzy, następnie po zatwierdzeniu macierz jest tworzona i losowana już na Form1,aby ją wyświetlić klikamy przycisk wyświetl i w textboxie na nowej formie ShowMatrix wyświetla nam macierze:


Forma1::
            ShowMatrix f2 = new ShowMatrix(trn.wyswietl(), tst.wyswietl());
            f2.ShowDialog();

Forma ShowMatrix:
        public ShowMatrix(string trn,string tst)
        {
            InitializeComponent();
            textBoxTRN.Text=(trn);
            textBoxTST.Text=(tst);

        } 

Klasa Macierz:
    public class Macierz
    {
        private double[,] tab;
        private int w;
        private int k;

        //właściwość wiersz
        public int Rows 
        {
            get { return w; } 
        }

        //właściwość kolumny
        public int Cols 
        { 
            get { return k; } 
        }

        //konstruktor Macierzy
        public Macierz(int wiersz, int kolumna)
        {
            this.w = wiersz;
            this.k = kolumna;
            this.tab = new double[w, k];
        }

        //właściwość dla przekazania macierzy do odczytu
        public double[,] GetMacierz()
        {
            // Need to return a clone of the array so that consumers            
            // of this library cannot change its contents            
            return (double[,])this.tab.Clone();
        }
        //indekser
        public double this[int rowIndex, int colIndex]
        {
            get { return this.tab[rowIndex, colIndex]; }
            set { this.tab[rowIndex, colIndex] = value; }
        }
}

Teraz na Form1 potrzebuje wywołać metode:

 
public static void euklides(double[,] d, double[,] trn, double[,] tst, int w1, int w2, int k)

Gdzie tablice trn i tst są tylko do odczytu a tablica d służy do zapisu wyniku.
Wywołanie metody:

euklides(d ???, trn.GetMacierz(), tst.GetMacierz(), trn.Rows, tst.Rows, trn.Cols) 

Pytanie:
Jak teraz stworzyć konstruktor w klasie Macierz aby można było nie tylko przesyłać tablice do odczytu ale także zapisywać na niej?
Próbuję tak:

Metody.euklides(d.GetMacierz(), trn.GetMacierz(), tst.GetMacierz(), trn.Rows, tst.Rows, trn.Cols) 

W metodzie ekulides próbuje zapisać wartości w tablicy d wykorzystując indekser: d[i][j]=x;

jednak gdy po wywołaniu metody prubuje wyświetlić zawartość tablicy d:
d.GetMacierz(); to pokazuje mi same 0, czyli nic nie zapisało się w tablicy ;/

Jeżeli jednak używam d[i][j]=x; normalnie na Form1 a nie w jakiejś metodzie to wszytko działa...

EDIT:
Wydaję mi się że zamiast private double[,] tab powinno być Public.
Zastanawiam się po co kładzie się taki wielki nacisk na całą tą hermetyzację???

0
  1. Indekser Macierz jest dwuargumentowy, więc macierz[i,j], a nie macierz[i][j]
  2. pomysł na macierz tylko do odczytu wg nie do końca trafiony, lepiej wyglądałoby to tak:
public class Macierz
{
	private double[,] tab;
	private int w;
	private int k;

	//właściwość wiersz
	public int Rows
	{
		get { return w; }
	}

	//właściwość kolumny
	public int Cols
	{
		get { return k; }
	}

	//konstruktor Macierzy
	public Macierz(int wiersz, int kolumna)
	{
		this.w = wiersz;
		this.k = kolumna;
		this.tab = new double[w, k];
	}

	//indekser
	public double this[int rowIndex, int colIndex]
	{
		get { return this.tab[rowIndex, colIndex]; }
		set { this.tab[rowIndex, colIndex] = value; }
	}
              public MacierzReadOlny GetReadOnlyMacierz() {return new MacierzReadOnly(this);}
}

public class MacierzReadOlny
{
	private Macierz _macierz;

	public MacierzReadOlny(Macierz m)
	{
		_macierz = m;
	}

	public int Rows { get { return _macierz.Rows; } }
	public int Cols { get { return _macierz.Cols; } }

	public double this[int rowIndex, int colIndex]
	{
		get { return _macierz[rowIndex, colIndex]; }
	}
}

więc
Metody.euklides(d, trn.GetReadOnlyMacierz(), tst.GetReadOnlyMacierz());
gdzie d jest typu Macierz, więc umożliwia także zapis wartości do tablicy.
Liczbę wierszy i kolumn wyczytujesz z właściwości pierwszej i drugiej macierzy. Najlepiej także sprawdzić liczbę kolumn czy w obu jest równa, jeśli nie wyrzucasz wyjątek.

Oczywiście jeśli chcesz bardziej uspójnić obie klasy (Macierz i MacierzReadOlny) mogą implementować jakiś interfejs(-y).

0
massther napisał(a)
  1. Indekser Macierz jest dwuargumentowy, więc macierz[i,j], a nie macierz[i][j]

Oczywiście chodziło mi o macierz[i,j] i tak jak mówie nie działa to w metodzie euklides

massther napisał(a)

więc
Metody.euklides(d, trn.GetReadOnlyMacierz(), tst.GetReadOnlyMacierz());
gdzie d jest typu Macierz, więc umożliwia także zapis wartości do tablicy.
Liczbę wierszy i kolumn wyczytujesz z właściwości pierwszej i drugiej macierzy.

a czy nie powinno być tak:

 Metody.euklides(d.tab, trn.GetReadOnlyMacierz(), tst.GetReadOnlyMacierz());

I wtedy w klasie Macierz: Public double[,] tab??

Bo inaczej to nie działa.
O takie coś chodziło?

0

Nie, dokładnie chodziło i o to co napisałem.

            Macierz t1 = new Macierz(3, 4);
            Macierz t2 = new Macierz(5, 4);
            Macierz d = new Macierz(5, 4);

            t1[1, 1] = 3;
            t2[1, 1] = 2;

            Metody.Euklides(d, t1.GetReadOnlyMacierz(), t2.GetReadOnlyMacierz());

            Debug.Write(d[1, 1]); // mamy tu 5.0, czyli poprawnie


        public static void Euklides(Macierz d, MacierzReadOlny t1, MacierzReadOlny t2)
        {
            if (t1.Cols != t2.Cols) throw new ArgumentException("Macierze mają różną liczbę kolumn.");

            d[1, 1] = t1[1, 1] + t2[1, 1];
        }

Pomijam że takie przekazanie macierzy d, jako parametru wyjściowego jest nie najtrafniejsze.
Generalnie to metoda Euklides powinna wiedzieć jaką macierz zwrócić na podstawie dwóch podanych, więc definicja metody powinna wyglądać tak:
public static Macierz Euklides(MacierzReadOlny t1, MacierzReadOlny t2)

Macierz d = Metody.Euklides(t1.GetReadOnly(), t2.GetReadOnly());

lub
public static void Euklides(out Macierz d, MacierzReadOlny t1, MacierzReadOlny t2)
w tym przypadku wywołanie wygląda tak:

Macierz d = null;
Metody.Euklides(out d, t1.GetReadOnly(), t2.GetReadOnly());
// a w Euklides
Euklides(...)
{
  d = new Macierz((int)Math.Max(t1.Rows,t2.Rows), t1.Cols);
  ...
}

Oczywiście preferowana jest propozycja nr 1: public static Macierz Euklides(MacierzReadOlny t1, MacierzReadOlny t2)

1 użytkowników online, w tym zalogowanych: 0, gości: 1