wiki:taulukot
Last modified 6 months ago Last modified on 2016-10-02 11:34:06

Sivu siirretty TIMiin

Luentomonisteen täydennykset » 1-ulotteiset taulukot

Yksiulotteinen taulukko on kuin rivitalo: selvittääksemme tietyn henkilön asunnon meidän tarvitsee tietää vain asunnon (järjestys-)numero.

https://trac.cc.jyu.fi/projects/ohj1/attachment/wiki/taulukot2D/rivitalo.png

Voimme esimerkiksi sanoa, että Pekka asuu rivitalon asunnossa nro 3, ja Maija asunnossa 0. Huomaa, että indeksit eli taulukon alkioiden laskeminen alkaa aina nollasta.

1. Taulukon esittely

Taulukko esitellään sanomalla taulukon alkioiden tyyppi, hakasulut ja taulukon nimi. Esimerkiksi:

int[] kuukausienPituudet;
double[] keskilampotilat;

2. Taulukon luominen

Erona tavalliseen muuttujaan taulukkomuuttuja on "vain" viite itse taulukkoon joka on jossakin muualla. Itse taulukko pitää luoda new TYYPPI[koko] kutsulla.

kuukausienPituudet = new int[12];
keskilammot = new double[31];  // tammikuun keskilämmöt.

Kun taulukko on luotu, ovat sen kaikki alkiot 0:ia.

3. Taulukon alkioon sijoittaminen

Taulukon indeksit alkavat 0:sta. Taulukon alkioon voidaan sijoittaa uusi arvo NIMI[INDEKSI] = LAUSEKE; Esimerkiksi:

kuukausienPituudet[0] = 31  // laitetaan tammikuun pituus
kuukausienPituudet[1] = 28; // laitetaan helmikuun pituus
kuukausienPituudet[11] = 31; // laitetaan joulukuun pituus
keskilammot[0] = -20.7; // Tammikuun 1. päivän keskilämpö
keskilammot[4] = -16.7; // Tammikuun 5. päivän keskilämpö

4. Taulukon alustaminen luonnin yhteydessä

Taulukko voidaan alustaa myös jo luomisen yhteydessä:

double[] keskilammot = {-20.7,-18.2,-10.3,-14.2,-16.7,-10.9};
string[] kuukausienNimet = {"tammi","helmi","maalis",...,"marras","joulu"};

5. Taulukon alkioiden summa

Taulukon alkioiden summa voitaisiin laskea:

int vuodenPituus = 0;
vuodenPituus  +=  kuukausienPituudet[0];
vuodenPituus  +=  kuukausienPituudet[1];
vuodenPituus  +=  kuukausienPituudet[2];
vuodenPituus  +=  kuukausienPituudet[3];
vuodenPituus  +=  kuukausienPituudet[4];
// ...
vuodenPituus  +=  kuukausienPituudet[9];
vuodenPituus  +=  kuukausienPituudet[10];
vuodenPituus  +=  kuukausienPituudet[11];

Tässä ei kuitenkaan ole hirveästi järkeä ja siksi otetaan käyttöön silmukat:

int vuodenPituus = 0;
for (int i=0; i < kuukausienPituudet.Length; i++)
{
    vuodenPituus  +=  kuukausienPituudet[i];
} 

Saman voi kirjoittaa myös muodossa:

int vuodenPituus = 0;
for (int i=0; i < kuukausienPituudet.Length; i++)
{
    int pituus = kuukausienPituudet[i];
    vuodenPituus  +=  pituus;
} 

ja tälle on lyhenteenä foreach-silmukka:

int vuodenPituus = 0;
foreach (int pituus in kuukausienPituudet)
{
    vuodenPituus  +=  pituus;
} 

6. Taulukkoja käsittelevien aliohjelmien testaaminen

6.1 Parametrina taulukko

Jos aliohjelmalle menee parametrina taulukko, voi tämän taulukon luoda etukäteen

///   double[] luvut = {1,2,3,2,5};
///   Keskiluku.Summa(luvut)             ~~~ 13; 

Taulukko voidaan luoda samalla kun aliohjelmaa kutsutaan

///   Keskiluku.Summa(new double[]{3,6}) ~~~ 9;

Mikäli aliohjelman taulukko on esitelty params avainsanalla:

public static double Summa(params double[] luvut)

voidaan viedä luettelona (toimii siis vain parametrilistan viimeisenä parametrina):

///   Keskiluku.Summa(3, 4, 5)             ~~~ 12;

6.2 Tuloksena taulukko

Mikäli funktio palauttaa taulukon, on testaaminen helpointa kun muuttaa palautetun taulukon merkkijonoksi ja vertaa tätä jonoa:

///   double[] luvut = Taulukot.ErotaLuvut("2 3 4 5 k      9 ;5");
///   String.Join(" ",luvut) === "2 3 4 5 0 9 5";  

Haasteita tulee jos tulee desimaaleja, koska desimaalimerkki vaihtelee. Tällöin pitää varmistaa tietty kulttuuri ennen testejä:

/// <summary>
/// Luodaan taulukko aloittaen x1:stä dx:n välein n kpl lukuja
/// </summary>
/// <param name="n">montaka alkiota tulee</param>
/// <param name="x1">alkuarvo</param>
/// <param name="dx">kasvatusaskel</param>
/// <returns>taulukko jossa n reaalilukua</returns>
/// <example>
/// <pre name="test">
///    System.Threading.Thread.CurrentThread.CurrentCulture 
///     = System.Globalization.CultureInfo.CreateSpecificCulture("en-US");
///    String.Join(" ",Listat.Lista(0,0.1,0.1)) === "";
///    String.Join(" ",Listat.Lista(1,0.2,0.1)) === "0.2";
///    String.Join(" ",Listat.Lista(4,0.1,0.2)) === "0.1 0.3 0.5 0.7";
/// </pre>
/// </example>
public static double[] Lista(int n, double x1, double dx)
{
    double[] luvut = new double[n];
    double x=x1;
    for (int i = 0; i < n; i++, x += dx)
       luvut[i] = x;
    return luvut;
}

Toinen vaihtoehto on käyttää jotakin itse tehtyä Jonoksi-aliohjelmaa, joka varmasti tuottaa haluttua desimaalisymbolia:

/// <summary>
/// Palauttaa taulukon merkkijonona niin, että alkioiden välissä on erotin.
/// Alkioden formaatin voi valita itse. Desimaalierotin on aina .
/// </summary>
/// <param name="luvut">Taulukko josta tehdään merkkijono</param>
/// <param name="sarakeErotin">Jono, jolla rivin alkiot erotetaan toisistaan</param>
/// <param name="sarakeformaatti"></param>
/// <example>
/// <pre name="test">
///  double[] luvut = {1,2.1,3};
///  Matriisit.Jonoksi(luvut) === "1 2.1 3";
///  Matriisit.Jonoksi(luvut,":","{0:0.0}") === "1.0:2.1:3.0";
///  Matriisit.Jonoksi((double[])null) === "null";
///  Matriisit.Jonoksi(new double[0]) === "";
/// </pre>
/// </example>
public static string Jonoksi<T>(T[] luvut, string sarakeErotin = " ", string sarakeformaatti = "{0}")
{
    if (luvut == null) return "null";
    string vali = "";
    StringBuilder rivi = new StringBuilder();
    System.Globalization.CultureInfo ci = System.Globalization.CultureInfo.CreateSpecificCulture("en-US");
    for (int ix = 0; ix < luvut.Length; ix++)
    {
        rivi.Append(vali); 
        rivi.Append(String.Format(ci,sarakeformaatti, luvut[ix]));
        vali = sarakeErotin;
    }
    return rivi.ToString();
}    

Linkkejä