Fält - indexerad variabel

Problemställning

Vid större program har man oftast behov av många variabler med samma syfte. Till exempel flera objekt som alla har sina x och y koordinater. Vi kunde skapa dessa med int x1, x2, x3, x4, .... med det blir ohanterligt i längden. Det vi behöver är ett variabel variabelnamn. Ett namn som är en kombinationa av ett namn (=bokstäver) och en siffra. För att använda en annanbild: Vi kommer att skapa en 'stor' variabel med namnet tal men instället för ett värde kan den håller ett större antal värden av samma typ. Tänk en låda tal som har flera fack. I varje fack kan du lagra ett tal.

BILD PÅ ARRAY

Loopen som iterar genom alla fältelement kan så klar göras med en while-sats eller en for sats. Här kommer kodexemplet med både och. while och for har i det här fallaet samma beteende.

Kodexempel

    import java.util.Random;
    //Variabler

        int[] tal = new int[20];  // skapa lådan (=fält) 'tal' med 20 fack
        Random rnd = new Random();


  void setup(){
    size(620,600);
    int i = 0;
    while( i < tal.length ){
        int slmp = rnd.nextInt(400)+50; // generera slumptal 50 .... 450 och spara i slmp
        tal[i] = slmp;                  // och spara i slmp
        i++;
    }

    for(int j = 0; j < tal.length; j++){  //loopar genom fältet 
        int pos = 10+j*30; 
        rect(pos, 10, 20, tal[j] );    // och använda tal[i] för rektangelns höjd 
    }
  }

För att förmedla tankesättet kommer här pseudokoden:

Pseudokod

i = 0
Sålänge i mindre fältets storlek
   Generera ett slumptal slmp
   Lagra slmp i tali
   höjd i med 1

i = 0
x = 10
Sålänge i mindre fältets storlek
   rita stapel på position x, höjden = tali
   höj i med 1
   höj x med 20

Detaljer

Observera att första elementet har numreringen noll (0), sista 19. På samma sätt som i ändrar sig 0 ... 19

tal.length motsvarar alltid antal element i fältet. Om man gör så här behöver man bra ändra int[] tal = new int[20] till int[] tal = new int[30] och allt fungera ändå!


Fältets storlek bestäms när den skapas ( int[] tal = new int[20]; ) . Det kan inte utökas i efterhand.

tal är ett fält (array) av int-variabler. Och då är varje tal[i] är i sin tur en int-variabel.
tal[0]++ eller tal[i] += 10 fungerar!

Array/fält är så klart inte begränsat till int. Det finns array för varje typ af variabel:

double[] decis = new double[10]; //   index/numrering  0...9 
float[]  floatis = new float[1000];
String[]  texter = new String[]; //(för text)
boolean[] skaRitas = new boolean[200];

int[] tal = {15,35,46,58,160,221,41,152,16};  

Sista raden: Man kan deklarera och initialisera (=fylla med värden) på en gång. Kompilatorn känner av att det är 9 tal och skapar ett motsvarande array/fält.

Laboration 1

1 Flytta andra loopen till draw()-blocket. De värden i tal (tal[0], tal[1], ....) används som höjd för varje stapel. Se till att staplarna blir mindre och mindre med varje omgång av draw(). Du måste, i en loop, minskar varje tal[i].

2 Vrid hela diagram från hängande staplar till stående eller liggande. Använd funktioner som ändra koordinatsystemet eller rita staplarna på ett annat sätt. Använd i så fall tali för rektanglens bredd och ändra y-koordinaten för rektangeln med 20 varje gång.

3 Skriv ett statisktikprogram. Fråga användaren efter tio tal och visa de som ett stapeldiagram. Här är pseudokoden som beskriver programmet:

Pseudokod

i = 0
Sålänge i mindre 10
   Fråga efter ett tal
   Lagra det i tali
   höjd i med 1

i = 0
x = 10
Sålänge i mindre 10
   rita stapel på position x, höjden = tali
   höj i med 1
   höj x med 20

Tips Programmet ska ju testas många gånger. Att varje omgång mata in 10 tal är jobbigt. När du har inläsningsloopen klar och vill fortsätter kan du (för testandet) istället deklarera och initialisera ett fält. Kom ihåg: Du kan avaktivera enstaka kodrader med // framför raden. ett helt block med / i början och / i slutet. Din kod kan sedan se ut så här:

 // int[] tal = new int[20];
 int[] tal = {15,35,46,58,160,221,41,152,16}; 


  /* 
  while(  .....


   } // end while

   */

   for( int i = 0; .....

4 Börja om med koden från första exemplet. Nu ska du markera största talet/längsta stapel med en egen färg (Du måste naturligtvis utgår ifrån att du inte vet det i förväg, även om du testar din kod med ett fördefinerad fält!). Programmet kommer består av tre loopar (iterationer)

  1. Fyll fället med slumptal (finns redan i exemplet, första loop)
  2. Hitta största tal (hitta på själv)
  3. Rita staplarna med särskild färg för den största/längsta. (finns delvis, är andra loopen, ska utökas med färgvalet)

loop 2 och 3 i pseudokod:

Pseudokod

// hitta största tal
max = // Vad borde sättas här?
i = 0
Sålänge i mindre 10
   om tali är större än max
      max = tali
   höj i med 1


// för att sedan rita alla staplar, en med särskild färg
i = 0
x = 10
Sålänge i mindre 10
   Om taltali = max
      sätt färg på grön
   annars sätt färg på vit

   rita stapel på position x, höjden = tali
   höj i med 1
   höj x med 20



5 Markera nu också den minsta stapeln.

6 Skriv ut alla värden under stapeln.

staplar med röd

7 Beräkna även summan av alla tal och medelvärdet. Visa även dessa två värden på skärmen. Medelvärdet kanske som linje över alla staplar?

Mus med array

I spel har man oftast flera objekt och då är det lämpligt att håller dessa informationer i en array. Ett enkel exempel hur man fyller två fält (posX, posY) med slumptal för positionen. I draw()-blocket rita cirklar med hälp av denna information:

    import java.util.Random;

    Random rnd = new Random();
    int FAELTSIZE = 20;
    int[] posX = new int[FAELTSIZE];
    int[] posY = new int[FAELTSIZE];
    int radie = 25;

    void setup(){
        size(800,800);
        // fyll fält med slumptal
        for(int j = 0; j < posX.length; j++){
        posX[j]  = rnd.nextInt(700)+50;
        posY[j]  = rnd.nextInt(700)+50;
        }
    }

    void draw(){
      background(0);

      //Rita alla cirklar
      for(int j = 0; j < FAELTSIZE; j++){ 
       ellipse(posX[j],posY[j],2*radie,2*radie); //med radie 25
        }
    }

Inget nytt här, det hade vi klarat utan fält. Men vi vill kunna klicka på en cirkel för att markera den. Vi behöver en extra variabel (int markedCircle = -1;) som håller den informationen. Vilken som klicktes på avgörs i mousePressed()-blocket. Med funktionen dist(float,float,float,float) kan vi bestämma avstånd mellan två punkter. I en loop beräknas avstånd för varje cirkel. om den är mindre än radien sparas platsnumret i markedCircle.

    import java.util.Random;

    Random rnd = new Random();
    int FAELTSIZE = 20;
    int[] posX = new int[FAELTSIZE];
    int[] posY = new int[FAELTSIZE];
    int markedCircle = -1; // -1 för att ingen ska vara markerad från början. 
    int radie = 25;

    void setup(){
        size(800,800);
        // fyll fält med slumptal
        for(int j = 0; j < posX.length; j++){
        posX[j]  = rnd.nextInt(700)+50;
        posY[j]  = rnd.nextInt(700)+50;
        }
    }

    void draw(){
      background(0);

      //Rita alla cirklar
      for(int j = 0; j < FAELTSIZE; j++){    // FAELTSIZE som alternativ till posX.length

        if(markedCircle == j  ) { fill(0,255,0); }
            else { fill(255); }

       ellipse(posX[j],posY[j],2*radie,2*radie); //med radie 25
        }
    }

    // dist mäta avstånd mellan två punkter (x1,y1) till (x2,y2)
    // med Pytagoras sats, kolla Reference
    void mousePressed(){
        for(int j = 0; j < FAELTSIZE; j++){
         float d =  dist( posX[j] , posY[j] , mouseX , mouseY ); //avstånd cirkelns mittpunkt och musen. 
         if(d < radie) { markedCircle = j;}
        }
    }

Info

Kolla Reference med högerklick på dist --> Find in Reference

Laboration 2

1 Nu gäller det att inte bara kunna markera en. Lägg till ett extra fält ( tex boolean[] new marked = boolean[FAELTSIZE]; ) (Minnesbild). for-satsen i mousePressed()-blocket kan redan nu avgöra vilken cirkel det har klickts på. motsvarande fältelement i marked kan sedan sättas på true: ( på rätt ställe: marked[j] = true; ) . I for-satsen som rita alla cirklar kan man sedan använda informationen från marked för att avgöra färgen: ( if marked[j] ) {....} ).

2 Inför knappkommando: När du trycker på r så raderas alla markeringar, med a markeras alla. Kolla Interaktion hur det var med knapptryckshändelser.

3 Med varje klick ska det försvinna en cirkel. Du kan göra så här att du sätter koordinaterna för rätt cirkel på (-100,-100) så att den ritas utanför fönstret och är därmed osynligt. Inte särskild effektiv med tanken att de utanför fönstret är ju ändå med i beräkningen och alla iterationer. Som utmaning kan du fundera på hur det borde göras!

foreach

För fält finns ett speciellt sätt att formulera en for-sats ( tagen från första kodexempel):

//vanligt 
for(int j = 0; j < tal.length; j++){  //loopar genom fältet 
        translate(30,0); 
    rect(10, 10, 20, tal[j] );    // och använda tal[i] för rektangelns höjd 
    }

//nytt
for(int element : tal){  //loopar genom fältet 
        translate(30,0); 
    rect(10, 10, 20, element );    // och använda tal[i] för rektangelns höjd 
    }

I andra for-satsen tas tal0, överförs till element och koden mellan måsvingarna utförs. Sedan överförs tal1 element och koden körs, sedan tal2 ... fram till sista värdet i fältet. I båda for-satser händer precis samma sak.

for(int t : tal ){
        int slmp = rnd.nextInt(400)+50; // generera slumptal 50 .... 450 och spara i slmp
        t = slmp;                     
    }

Övning

Ta en av övningar och gör om vanliga for-satser till den nya formen.

fler exempel:

Fältdeklaration Passande for-sats
float[] vinkel = new float[20]; for(float v : vinkel) { .......}
double[] parameter = new double[20]; for(double prm : parameter) { .......}
String[] namn = new String[100]; for(String n : namn) { .......}

Knäcka isär en sträng

När program koomunicera med andra program överförs data oftast i ett enda flöde (stream) från sändaren till mottagren. Kolla till exempel en internet länk till en produktsida.

https://www.amazon.de/Inakustik-High-End-Netzwerkkabel-CAT7-L%C3%A4nge/dp/B0088B0D8M/ref=pd_sbs_147_8?_encoding=UTF8&pd_rd_i=B0088B0D8M&pd_rd_r=572fbd00-2941-11e9-9554-5bcb7413d47b&pd_rd_w=KgwuQ&pd_rd_wg=6JNQ5&pf_rd_p=74d946ea-18de-4443-bed6-d8837f922070&pf_rd_r=5A436ZM4MX1CAK296XQT&psc=1&refRID=5A436ZM4MX1CAK296XQT

Der här skickas till servern (amzon.de). Och prgrammet måste sedan plockar isär denna teckenföljd ( = String ) för att komma åt alla informationsbitar. Det finns även sådana funktioner i processing/java:

    //Variabler

void setup(){

  String allaParameter = "_encoding=UTF8&pd_rd_i=B0088B0D8M&pd_rd_r=572fbd00-2941-11e9-9554-5bcb7413d47b&pd_rd_w=KgwuQ&pd_rd_wg=6JNQ5&pf_rd_p=74d946ea-18de-4443-bed6-d8837f922070&pf_rd_r=5A436ZM4MX1CAK296XQT&psc=1&refRID=5A436ZM4MX1CAK296XQT";

  String[] paras = allaParameter.split("&");

  println("Strängen har " +  paras.length + " parameterpar:");

  for(int i = 0; i < paras.length;i++){
    println(paras[i]);
  }

  println("\n");
  //eftersom vi vet att varje para har två delar:

  for(int i = 0; i < paras.length;i++){
    String[] rader = paras[i].split("=");

    String nyckel = rader[0];
    String verde = rader[1];

    println( nyckel + "\t---> " + verde);
  }

}

Det avgörande raderna är String[] paras = allaParameter.split("&"); . Här tas strängen allaParameter och splittras och överföras till ett fält av strängar (paras); Skiljetecken är '&' och den försvinner under processen. I String[] rader = paras[i].split("="); händer samma sak. paras[i] är en sträng som i sin tur kan splittar med '=' .

Sammanfattning

Sammanfattning

  • Ett fält är en speciell variabelform som tillåter indexering
  • Index börja alltid vid 0
  • Deklaration som vanligt men [] och new kommer till: int[] tal = new int[100];
  • Det finns ett speciellt sätt att formulera en for-sats i samband med fält om man ändå ska itera (går genom) alla element i fältet.