mieszanie tablicy

0

Witam

Mam tablice dwuwymiarową (np.100 wierszy i 5 kolumn z liczbami całkowitymi) i teraz potrzebuje napisać funkcje która poprzestawia kolejność wierszy.
Mój pomysł:

w = wiersze
k = kolumny
kopiaTablicy = przekopiowana do listy list tablica

 
Random a = new Random();
int c,b;

                for (int i = w; i > 0; i--)
                {
                    b=a.Next(0, i);

                    for (int j = 0; j < k; j++)
                    {
                        
                        tab[i, j] = kopiaTablicy[b][j];
                        kopiaTablicy.RemoveAt(b);
                    }
                }

Jednak trzeba przy każdym wywołaniu metody przekopiować oryginalna tablice do listy list.
Czy ten sposób jest Ok, czy jednak macie może jakieś inne prostsze pomysły?

0

"rozpakuj" tablice do luzno latajacych wierszy zgromaczonych w List<>, i potem w oparciu o generator losowy wykonuj zamiane wierszy miejscami na liscie w klasycznym stylu
var tmp = lista[i];
lista[i] = lista[j];
lista[j] = tmp;
potem, "upakuj" z powrotem wiersze z listy do np. nowej tablicy.

edit: zamiast List<int[]>, mozesz tez uzyc rownie dobrze int[][] zamiast int[,] itp. Jesli nie chcesz rozbijac tymczasowo tablicy na wiersze, to i tak nie musisz za kazdym razem kopiowac tablicy - wykonuj zamiane wg. tych trzech linii powyzej tyle ze na poszczegolnych komorkach zamienianych wierszy. w zaleznosci od wielkosci tablicy i ilosci 'losowan', moze to nawet byc czasem szybsze od rozbijania na wiersze.

0

w przypadku tablicy zagnieżdżonej (w przeciwieństwie do dwuwymiarowej) operacja jest banalna:

using System;

class Program {

   static int[][] tablica;

   static void Wypisz() {
      for (int i=0;i<10;i++) {
         for (int j=0;j<10;j++) {
            Console.Write(tablica[i][j]);
            Console.Write(' ');
         }
         Console.WriteLine();
      }
   }

   static void Main() {
      tablica = new int[10][];
      for (int i=0;i<10;i++) tablica[i] = new int[10];
      for (int i=0;i<10;i++)
         for (int j=0;j<10;j++)
            tablica[i][j] = i+12*j;
      Wypisz();
      Array.Reverse(tablica);
      Console.WriteLine();
      Wypisz();
   }

}
0

Zrobiłem tak:

 
public void Przemieszaj()
        {
            Random a = new Random();
            Random b = new Random();
            int c,d;

            //kopiowanie tablicy
            for (int i = 0; i < w; i++)
            {
                for (int j = 0; j < k; j++)
                {
                    this.pomieszanaTab[i, j] = this.tab[i, j];
                }
            }

            for (int i = 0; i < w; i++)
            {
                c = a.Next(0, w - 1);
                d = b.Next(0, w - 1);
                if (c == d) d = b.Next(0, w - 1);

                for (int j = 0; j < k; j++)
                {
                    double tmp = this.pomieszanaTab[c, j];
                    this.pomieszanaTab[c, j] = this.pomieszanaTab[d, j];
                    this.pomieszanaTab[d, j] = tmp;
                }
            }

        }

Teraz mam jednak większy problem:
Potrzebuję tą tablice podzielić na n równych elementów (niech n będzie w przedziale od 2 do 5).

Myślałem zrobić tak mniej więcej tak:

 
podzialka = wiersze/n
a=0;

for (int i=0; i<wirsze; i++)
{
  for (int j=0; j < kolumny; j++)
  {
   if ( i < podziałka)                               tab1[i,j]=tab[i,j];
   if ( i < podziałka*2 && i>podziałka)     tab2[a,j]=tab[i,j];
   if ( i < podziałka*3 && i>podziałka*2) tab3[a,j]=tab[i,j];
   if ( i < podziałka*4 && i>podziałka*3) tab4[a,j]=tab[i,j];
   if ( i < podziałka*5 && i>podziałka*4) tab5[a,j]=tab[i,j];
   }
   a++;
   if (a == podzialka) a=0;
}

Jednak tym sposobem muszę mieć stworzone od razu 5 tablic, mimo ze mogę potrzebować np tylko dwóch.
Dochodzi jeszcze problem z ostatnio tablicą, która przecież może być mniejsze od pozostałych (np. dla 99 wierszy i n=5, mamy 4x20 + 1x19).

0

pierwsze:
podzielic tablice na N rownych części? a jak to ma się zachować gdy równy podzial jest niemożliwy? (np. owo 99->4x20+1x19). nie my, tylko TY MASZ TO WIEDZIEC, poniewaz Tobie dano jakies tam zadanie i chcesz cos osiagnac, ja/my go nie znamy. nie wiesz? zapytaj tego kto Ci tak kazal podzielic, albo opisz co chcesz faktycznie osiagnac/co bedziesz potem tylko kawalkami robic

drugie:
na N częsci ale wg. ktorego wymiaru? wierszami? kolumnami? czy "ciurkiem" tzn: gdy tablica 3x3 ma wiersze: 1,1,1 i 2,2,2 i 3,3,3 to podzial na 2 ma dac: 1,1,1,2,2 i 2,3,3,3,x ? to tez ma wariacje pion-poziom. zdefiniuj, co to znaczy "podzielic tablice dwuwymiarowa na N czesci". od tego zalezy jak powinien wygladac kod dokonujacy podzialu. jesli wierszami/kolumnami bez 'podbierania' z wiersza/kolumny nastepnej, to zadnej "podzialki" nie potrzebujesz, wystarczy pobawic odpowiednio sie dodawaniem dzieleniem i mnozeniem na zmiennych i oraz j po ktorych krecisz petlami

po trzecie:
skoro znasz N a takze znasz dlugosc danego wymiaru tablicy (http://msdn.microsoft.com/en-us/library/system.array.getlength.aspx) to z prostego dzielenia A/B otrzymasz ilosc wynikowych tabliczek jakie potrzebujesz na wynik. ilosc moze byc zanizona o 1 jesli liczby nie dziela sie bez reszty.

po czwarte:
znajac dokaldna ilosc wynikowych tabliczek, mozesz ich sobie przygotowac dokladnie tyle, bez nadmiaru, bez obawy o niedomiar

0
quetzalcoatl napisał(a)

pierwsze:
podzielic tablice na N rownych części? a jak to ma się zachować gdy równy podzial jest niemożliwy? (np. owo 99->4x20+1x19). nie my, tylko TY MASZ TO WIEDZIEC, poniewaz Tobie dano jakies tam zadanie i chcesz cos osiagnac, ja/my go nie znamy. nie wiesz? zapytaj tego kto Ci tak kazal podzielic, albo opisz co chcesz faktycznie osiagnac/co bedziesz potem tylko kawalkami robic

Tak jak pisałem dzielimy na N części (n od 2 do 5) i dezeli da się to mają to być równe części, jeżeli nie to ostatnia ma być wielkości tej reszty z dzielenia. Dzielimy po wierszach.
Czyli tak jak pisałem w przykładzie: mając 100 wierszy i n=5 to mamy 5 tablic x20 wierszy. Gdy liczba wierszy równa się 99 i n=4 to wtedy powinno być tak: 3x25 + 1x24.

Dla zainteresowanych - mam kilka algorytmów które chce sprawdzić za pomocą walidacji CV-n, i potrzebuje napisać najpierw algorytm dzielący mi systemy na te n-części.

0

pisze bez kompilowania i IDE wiec moga byc literowki, bledy itede, chodzi o idee:

int dlugoscwiersza = 20;
int wiersze = 99
int czesci = 4

int ilosc_pelnych_tabliczek = wiersze / czesci ;
int wiersze_w_tabliczce = wiersze / ilosc_pelnych_tabliczek;

int dlugosc_resztki = wiersze % czesci ;
bool czy_jest_koncowka = dlugosc_resztki != 0;

List<int[,]> wynik = new List<int[,]>();
for(int i=0; i<ilosc_pelnych_tabliczek; ++i)
{
    int[,] kawalek = new int [wiersze_w_tabliczce,dlugoscwiersza]; // moglem zamienic x/y miejscami, sprawdz
    for(int wiersz = 0; wiersz < wiersze_tabliczce; wiersz++)
        for(int kolumna = 0; koluna < dlugoscwiersza; kolumna++)  // zamiast tej petli, mozliwe ze mozna uzyc czegos a'la Array.Copy
            kawalek[wiersz,kolumna] = tablica[ i*wiersze_w_tabliczce + wiersz, kolumna];
    wynik.Add(kawalek);
}

if(czy_jest_koncowka)
{
    int[,] kawalek = new int [dlugosc_resztki,dlugoscwiersza]; // moglem zamienic x/y miejscami, sprawdz
    ...prawie identyczne kopiowanie...
    wynik.Add(kawalek);
}

jezeli potrzebujesz miec to nie w List<int[]> tylko czyms innym, kod bedzie wygladal dosc podobnie, tylko linie obslugi kontenera beda wygladac inaczej.
np. jesli potrzebujesz miec to w int[][,] to bedziesz musial zewnetrzna tablice o dlugosci "ilosc_tabliczek+(czy_jest_koncowka?1:0)" przygotowac sobie przed petlami, itp.

0

wprowadziłem podobną implementacje:

                     int czesci = (int)numericWalidacja.Value;

                    tablica = new List<Macierz>();

                    int wiersze_w_tabliczce= trn.Rows / czesci;
                    //int ilosc_pelnych_tabliczek = trn.Rows / wiersze_w_tabliczce;
                  
                    int wiersze_resztki = trn.Rows % czesci; //ostatnia tablica
                    bool czy_jest_koncowka = wiersze_resztki != 0; //sprawdzanie czy ostatnia jest innego rozmiaru

                    if (czy_jest_koncowka) czesci--;

                    for (int i = 0; i < czesci; i++)
                    {
                        tablica.Add(new Macierz(i * wiersze_w_tabliczce, (i + 1) * wiersze_w_tabliczce, wiersze_w_tabliczce, trn.Cols, trn.GetMacierz()));
                    }
                    if (czy_jest_koncowka)
                    {
                        tablica.Add(new Macierz(czesci * wiersze_w_tabliczce, trn.Rows, wiersze_resztki, trn.Cols, trn.GetMacierz()));
                    }

ale dalej jest spory problem. Pokaże na przykładzie:

Wszystko jest ok dla 99 wierszy i k=2.

ale dla tablicy, która ma 101 wierszy i k=2 (ma być dzielona na dwie części) wyjdzie:
1x50 i 1x1 (zamiast 1x50 i 1x51)

znowu twoją implementacją wychodziloby:
2x50 i 1x1

EDIT:
Mam pomysł:
przy dzieleniu zaokrąglać liczby w góre:
dla 101:2 będzie 51 i 50
dla 101:3 będzie 34,34,33
dla 99:2 bedzie 50 i 49

Tylko teraz jak to przelać w kod ;p

EDIT 2:
znalazłem funkcję ceiling:

 
int wiersze_w_tabliczce = (int)Math.Ceiling((double)trn.Rows / (double)czesci); 

to teraz lece dalej ;p

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