Manche Zahlen und Objekte speichere ich in einer ArrayList. Hier kann man relativ leicht Objekte hinzufügen (.add()) oder entfernen (.remove()). In diesem Artikel beschreibe ich, wie man den größten und den kleinsten Wert (Minumum und Maximum) einer ArrayList bestimmt.
Für eine ArrayList<Integer>
Am einfachsten ist die Bestimmung des Minimums und des Maximums bei einer Liste von Objekten mit einer natürlichen Reihenfolge, wie z.B. Integer-Zahlen. In dem Falle kann man die statischen Methoden max() und min() der Collections-Klasse verwenden. Je nachdem wie die Liste aufgebaut ist, kann es allerdings auch effizientere Wege geben (siehe Stackoverflow und Zparacha-Blog).
ArrayList<Integer> liste =new ArrayList<Integer>();
liste.add(100);
liste.add(200);
liste.add(110);
liste.add(99);System.out.println("Maximum: "+Collections.max(liste));System.out.println("Minimum: "+Collections.min(liste));
ArrayList<Integer> liste = new ArrayList<Integer>();
liste.add(100);
liste.add(200);
liste.add(110);
liste.add(99);
System.out.println("Maximum: " + Collections.max(liste));
System.out.println("Minimum: " + Collections.min(liste));
Vollständiges Beispiel:
packagede.fenon.test;importjava.util.ArrayList;importjava.util.Collections;importjava.util.Random;/**
* Beispiel: Kleinsten und größten Wert in einer ArrayList finden.
* @author fenon.de
*/publicfinalclass HauptProgramm {/** Zahl der Messungen. */staticfinalInteger STICHPROBE =10;/** Maximalwert. */staticfinalInteger MAXIMUM =10;/** Seed des Zufallszahlen-Generators. */staticfinalInteger SEED =1234567891;/**
* Privater Konstruktor.
* Dadurch kann kein Objekt der Klasse "Hauptprogramm" erzeugt werden.
*/private HauptProgramm(){}/**
* main()-Methode.
* @param args - Parameter der Kommandozeile.
*/publicstaticvoid main(finalString[] args){
ArrayList<Integer> liste =new ArrayList<Integer>();// Erzeuge zufällige MesswerteRandom generator =newRandom(SEED);for(int i =0; i < STICHPROBE; i++){
liste.add(generator.nextInt(MAXIMUM));}// Gib die Messwerte ausfor(Integer element:liste){System.out.println(element);}// Gib Kleinsten und Größten Wert ausSystem.out.println("Maximum: "+Collections.max(liste));System.out.println("Minimum: "+Collections.min(liste));}// ENDE: main()}// ENDE: HauptProgramm
package de.fenon.test;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Random;
/**
* Beispiel: Kleinsten und größten Wert in einer ArrayList finden.
* @author fenon.de
*/
public final class HauptProgramm {
/** Zahl der Messungen. */
static final Integer STICHPROBE = 10;
/** Maximalwert. */
static final Integer MAXIMUM = 10;
/** Seed des Zufallszahlen-Generators. */
static final Integer SEED = 1234567891;
/**
* Privater Konstruktor.
* Dadurch kann kein Objekt der Klasse "Hauptprogramm" erzeugt werden.
*/
private HauptProgramm() {}
/**
* main()-Methode.
* @param args - Parameter der Kommandozeile.
*/
public static void main(final String[] args) {
ArrayList<Integer> liste = new ArrayList<Integer>();
// Erzeuge zufällige Messwerte
Random generator = new Random(SEED);
for (int i = 0; i < STICHPROBE; i++) {
liste.add(generator.nextInt(MAXIMUM));
}
// Gib die Messwerte aus
for (Integer element:liste) {
System.out.println(element);
}
// Gib Kleinsten und Größten Wert aus
System.out.println("Maximum: " + Collections.max(liste));
System.out.println("Minimum: " + Collections.min(liste));
} // ENDE: main()
} // ENDE: HauptProgramm
Für eine ArrayList mit komplexeren Objekten
Man kann allerdings auch den minimalen und maximalen Wert eigener/komplexerer Objekte bestimmen. Im folgenden Beispiel habe ich eine Liste von Objekten des eigenen Typs Website. Mit Hilfe eines Comparators (hier: VergleicheHits) kann festgelegt werden, wie die Objekte verglichen werden sollen. Im Beispiel werden die Website-Objekte dann anhand ihrer Zugriffzahlen verglichen.
Klasse: Website
packagede.fenon.Website;/**
* Informationen über Webseite.
* @author fenon.de
*/publicclass Website {/** Zahl der Besucher der Website. */privateInteger hits;/**
* Konstruktor.
* @param besuche - Zahl der Besucher.
*/public Website(finalInteger besuche){this.setHits(besuche);}// ENDE: Konstruktor/**
* Gibt die Besucherzahl der Webseite aus.
* @return Zahl der Besucher der Website.
*/publicfinalInteger getHits(){return hits;}// ENDE: getHits()/**
* Setze die Besucherzahl der Webseite.
* @param besuche - Zahl der Besucher.
*/publicfinalvoid setHits(finalInteger besuche){this.hits= besuche;}// ENDE: setHits()}// ENDE: Website
package de.fenon.Website;
/**
* Informationen über Webseite.
* @author fenon.de
*/
public class Website {
/** Zahl der Besucher der Website. */
private Integer hits;
/**
* Konstruktor.
* @param besuche - Zahl der Besucher.
*/
public Website(final Integer besuche) {
this.setHits(besuche);
} // ENDE: Konstruktor
/**
* Gibt die Besucherzahl der Webseite aus.
* @return Zahl der Besucher der Website.
*/
public final Integer getHits() {
return hits;
} // ENDE: getHits()
/**
* Setze die Besucherzahl der Webseite.
* @param besuche - Zahl der Besucher.
*/
public final void setHits(final Integer besuche) {
this.hits = besuche;
} // ENDE: setHits()
} // ENDE: Website
Comparator: VergleicheHits
packagede.fenon.Website;importjava.util.Comparator;/**
* Vergleiche Website-Objekte anhand ihrer Hits.
* @author fenon.de
*/publicclass VergleicheHits implements Comparator<Website>{/** Konstruktor. */public VergleicheHits(){}
@Override
publicfinalint compare(final Website a, final Website b){if(a.getHits()< b.getHits()){return-1;}elseif(a.getHits().equals(b.getHits())){return0;}else{return1;}}// ENDE: compare()}// ENDE: VergleicheHits
package de.fenon.Website;
import java.util.Comparator;
/**
* Vergleiche Website-Objekte anhand ihrer Hits.
* @author fenon.de
*/
public class VergleicheHits implements Comparator<Website> {
/** Konstruktor. */
public VergleicheHits() {}
@Override
public final int compare(final Website a, final Website b) {
if (a.getHits() < b.getHits()) {
return -1;
} else if (a.getHits().equals(b.getHits())) {
return 0;
} else {
return 1;
}
} // ENDE: compare()
} // ENDE: VergleicheHits
Das Beispiel
packagede.fenon.test;importjava.util.ArrayList;importjava.util.Collections;importjava.util.Random;importde.fenon.Website.VergleicheHits;importde.fenon.Website.Website;/**
* Beispiel: Kleinsten und größten Wert in einer Liste finden.
* @author fenon.de
*/publicfinalclass HauptProgramm {/** Zahl der Messungen. */staticfinalInteger STICHPROBE =10;/** Maximalwert. */staticfinalInteger MAXIMUM =10;/** Seed des Zufallszahlen-Generators. */staticfinalInteger SEED =1234567891;/**
* Privater Konstruktor.
* Dadurch kann kein Objekt der Klasse "Hauptprogramm" erzeugt werden.
*/private HauptProgramm(){}/**
* main()-Methode.
* @param args - Parameter der Kommandozeile.
*/publicstaticvoid main(finalString[] args){
ArrayList<Website> seiten =new ArrayList<Website>();// Erzeuge zufällige MesswerteRandom generator =newRandom(SEED);for(int i =0; i < STICHPROBE; i++){
seiten.add(new Website(generator.nextInt(MAXIMUM)));}// Gib die Messwerte ausfor(Website element:seiten){System.out.println("Hits: "+ element.getHits());}// Gib Kleinsten und Größten Wert aus.// Mit einem anderen Getter könnte man z.B. den Namen der Website ausgeben.System.out.println("Maximum: "+Collections.max(seiten, new VergleicheHits()).getHits());System.out.println("Minimum: "+Collections.min(seiten, new VergleicheHits()).getHits());}// ENDE: main()}// ENDE: HauptProgramm
package de.fenon.test;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Random;
import de.fenon.Website.VergleicheHits;
import de.fenon.Website.Website;
/**
* Beispiel: Kleinsten und größten Wert in einer Liste finden.
* @author fenon.de
*/
public final class HauptProgramm {
/** Zahl der Messungen. */
static final Integer STICHPROBE = 10;
/** Maximalwert. */
static final Integer MAXIMUM = 10;
/** Seed des Zufallszahlen-Generators. */
static final Integer SEED = 1234567891;
/**
* Privater Konstruktor.
* Dadurch kann kein Objekt der Klasse "Hauptprogramm" erzeugt werden.
*/
private HauptProgramm() {}
/**
* main()-Methode.
* @param args - Parameter der Kommandozeile.
*/
public static void main(final String[] args) {
ArrayList<Website> seiten = new ArrayList<Website>();
// Erzeuge zufällige Messwerte
Random generator = new Random(SEED);
for (int i = 0; i < STICHPROBE; i++) {
seiten.add(new Website(generator.nextInt(MAXIMUM)));
}
// Gib die Messwerte aus
for (Website element:seiten) {
System.out.println("Hits: " + element.getHits());
}
// Gib Kleinsten und Größten Wert aus.
// Mit einem anderen Getter könnte man z.B. den Namen der Website ausgeben.
System.out.println(
"Maximum: "
+ Collections.max(seiten, new VergleicheHits()).getHits()
);
System.out.println(
"Minimum: "
+ Collections.min(seiten, new VergleicheHits()).getHits()
);
} // ENDE: main()
} // ENDE: HauptProgramm
Manchmal liegen in R Daten in Form einer Liste vor (z.B. die Ausgabe der Funktion hist()). In einer Liste können Daten enthalten sein, die eine unterschiedliche Länge haben. Im Falle von hist() sind z.B. Arrays unterschiedlicher Länge gemeinsam mit einfachen Variablen in einer Liste kombiniert.
Für weitere Analysen kann es jedeoch hilfreich sein, die gleich langen Teile in einen separaten data.frame auszulagern. Dann kann z.B. mit Hilfe der Funktion subset() relativ einfach Bereiche aus den Daten herausfiltern.
In R gibt es keine vorgefertigte Funktion, die direkt Daten vom Typ list in Daten vom Typ data.frame konvertieren kann. Das liegt daran, dass in einem data.frame alle enthaltenen Variablen (in der Regel Arrays) die gleiche Länge haben müssen. Unsere Entscheidung, welche Variablen aus der Liste in den data.frame übernommen werden sollen, müssen wir R mitteilen.
Das folgende Beispiel zeigt, wie man das sehr einfach bewerkstelligen kann:
1
2
3
4
5
6
7
8
# Liste mit Arrays ("x", "y", "sd") und einer Variablen ("name")
liste =list(x=c(1:5), y=c(11:15), sd=c(0,1,2,0,0), name="Meine Liste")# data.frame ("df") erzeugen mit den Variablen "x", "y" und "sd"df=with(data=liste, expr=data.frame(x, y))# Struktur des data.frames ausgebenstr(df)
# Liste mit Arrays ("x", "y", "sd") und einer Variablen ("name")
liste = list(x=c(1:5), y=c(11:15), sd=c(0,1,2,0,0), name="Meine Liste")
# data.frame ("df") erzeugen mit den Variablen "x", "y" und "sd"
df = with(data=liste, expr=data.frame(x, y))
# Struktur des data.frames ausgeben
str(df)
'data.frame': 5 obs. of 3 variables:
$ x : int 1 2 3 4 5
$ y : int 11 12 13 14 15
$ sd: num 0 1 2 0 0
Im Anschluss kann man sehr einfach nur bestimmte Teile des data.frame ausgeben lassen.
Das kann man z.B. direkt über den Index (df[zeile, spalte]) oder über die Funktion subset() machen.
1
2
3
4
5
6
7
8
9
# Nur das zweite und vierte Element (Zeile) anzeigendf[c(2,4),]# Nur die Elemente (Zeilen) anzeigen, bei denen x>2 istdf[(df$x>2),]# Nur die Elemente (Zeilen) der Variablen (Spalten) x und y ausgeben,# bei denen sd<1 und x>2 istsubset(df, subset=(x>2& sd<1), select=c(x,y))
# Nur das zweite und vierte Element (Zeile) anzeigen
df[c(2,4),]
# Nur die Elemente (Zeilen) anzeigen, bei denen x>2 ist
df[(df$x>2),]
# Nur die Elemente (Zeilen) der Variablen (Spalten) x und y ausgeben,
# bei denen sd<1 und x>2 ist
subset(df, subset=(x>2 & sd<1), select=c(x,y))
Stell Dir vor, Du hast die Länge von 1000 Fischen gemessen. Im Anschluss möchtest Du die eine Häufigkeitsverteilung (Histogramm) der Größen erstellen. Je nachdem wie genau du gemessen hast, wirst du keine zwei Fische mit der gleichen Länge finden. Daher bist Du gut beraten, die Daten zunächst in bestimmte Längenklassen einzuteilen (z.B. „Anzahl von Fischen zwischen 23cm und 24cm“). Für diese Klassifizierung (binning) steht Dir in R die Funktion hist() zur Verfügung.
Nehmen wir mal an, die Längen der Fische folgen einer Normalverteilung. Im Durschnitt haben die Fische eine Länge von 25cm (± 5cm)
1
2
3
# Ziehe Eintausend Zufallszahlen aus einer Normalverteilung# (Mittelwert: 25; Standardabweichung: 5)
laengen =rnorm(n=1e3, mean=25, sd=5)
# Ziehe Eintausend Zufallszahlen aus einer Normalverteilung
# (Mittelwert: 25; Standardabweichung: 5)
laengen = rnorm(n=1e3, mean=25, sd=5)
Mit der Funktion hist() kannst Du die Daten nun in Klassen einteilen und plotten lassen.
1
2
3
# Klassifiziere die Daten# (=Erstelle eine Histogramm und stelle es dar)
gebinnt =hist(laengen, plot=TRUE)
# Klassifiziere die Daten
# (=Erstelle eine Histogramm und stelle es dar)
gebinnt = hist(laengen, plot=TRUE)
Automatisch erstelltes Histogramm der Beispieldaten. Die Klassengrenzen wurden von R bestimmt.
hist() erstellt nun eine list, in der die Klassengrenzen (breaks), die Häufigkeiten (counts), Dichten (densitiy) und Klassenmitten (mids), sowie der Name der ursprünglichen Variable (xname) und die Information, ob die Klassen alle gleich groß sind (equidist), gespeichert werden:
Du hast natürlich auch die Möglichkeit, selbst Klassengrenzen (breaks) anzugeben. Die Klassen müssen auch nicht alle gleich Groß sein. Bei einigen Daten können z.B. logarithmische Bin-Größen sinnvoll sein.
Histogramm mit selbst gewählten Klassengrenzen (hier: Klassenbreite=1cm)
Hierbei muss man allerdings darauf achten, dass keiner der Werte ausgeschlossen wurde, weil er ausserhalb der gewählten Klassen lag bzw. auf die untere (oder obere) Klassengrenze gefallen ist.
Fehler in hist.default(laengen, plot = T, breaks = c(15:50), xlab = "Länge (cm)", :
einige 'x' nicht gezählt: evtl. überdecken die 'breaks' nicht den gesamten Bereich von 'x'
Daher sollte man immer prüfen, ob die Summe der Werte in den Klassen auch tatsächlich der Stichprobengröße entspricht.
# Sind alle Messwerte der Stichpobe im Histogramm berücksichtigt?sum(gebinnt$counts)
# Sind alle Messwerte der Stichpobe im Histogramm berücksichtigt?
sum(gebinnt$counts)
Eventuell muss man dann weitere Klasse hinzunehmen, bzw. die untere (oder obere) Klassengrenze zu einer Klasse hinzu zählen (Option include.lowest=T).
Alternativen
Alternativ zur Funktion hist() könnte man ein Histogramm auch durch die Anwendung der Funktion table() auf gerundete Daten (round()) erstellen: table(round(daten)).
Die Funktion table() ist dazu gedacht die „Anzahl gleicher Werte zu ermitteln“. Das entspricht aber nicht ganz dem Gedanken der Klassifizierung.