C# Index?


31.07.2020, 13:49

Hier ist übrigens der Quelltext zu meiner Variante:

//Zweitkleinstes Element im Array:

           int smallest = ary[0];

           int secondSmallest = ary[0];

           

           for(int i=1; i<ary.Length; i++)

           {

               if(ary[i]<smallest)

               {

                   smallest = ary[i];

               }

               if ((ary[i] < secondSmallest) && (ary[i] != smallest))

               {

                   secondSmallest = ary[i];

               }

           }

           Console.WriteLine("Das zweitkleinste Element im Array hat den Wert:" + secondSmallest);

PS: Der einzige Unterschied zur Variante 1 ist, dass smallestIndex weggelassen wurde

verreisterNutzer  31.07.2020, 13:51

Bitte tu den Code in

So etwas

xD

LiLGemmeck 
Fragesteller
 31.07.2020, 14:08

Ja gut danke dann weiß ich für die Zukunft bescheid

6 Antworten

Vom Fragesteller als hilfreich ausgezeichnet

Deine Varianten haben leider beide einen kleinen Denkfehler ...

Was ist denn wenn ary[0] bereits die kleinste Zahl ist?

Die Initialisierung hat dann den Effekt, dass smallest = secondsmallest und kein Wert mehr < smallest oder seconsmallest.

Woher ich das weiß:Berufserfahrung – Senior-Softwaredeveloper mit 20 Jahren Berufserfahrung.
WitchHunter0815  31.07.2020, 14:49

Ich denke so in der Art wirst du zum Ziel kommen:

int smallest = Int32.MaxValue;
int secondSmallest = Int32.MaxValue;

if (ary.Length > 1)
{
  for(int i = 0; i < ary.Length; i++)
  {
    if(ary[i] < smallest)
    {
      secondSmallest = smallest;
      smallest = ary[i];
    }
    else if(ary[i] < secondSmallest)
    {
      secondSmallest = ary[i];
    }
  }
}
else 
{
  throw new ArgumentOutOfRangeException(nameof(ary));
}

Console.WriteLine($"Das zweitkleinste Element im Array hat den Wert: {secondSmallest}");
1
wooghie78  31.07.2020, 15:53
@WitchHunter0815

Die else if() macht hier Sinn, um secondSmallest zu präzisieren.

smallest ist jedoch die Eingangskondition zu secondSmallest, daher sind vorab gegebenenfalls möglicher Präzisierungen zunächst beide gleichgesetzt, erst dann bildet smallest den nächsten Testfall.

Man behandelt den Überlauf auf diese Art der if-Kondition, der für den Letztfall zustande kommt.

Anders gesagt, vergibst du smallest nur neu nach vorhergehender Feststellung von secondSmallest, da in der Schleife noch die Möglichkeit einer weiteren Prüfung anstehen könnte. Prinzipiell ist dir smallest jedoch egal.

Tritt der Fall zudem ein weiteres Mal ein, dann überschreibt sich secondSmallest eben noch ein weiteres Mal, ehe es dann zum Auslauf der Schleife kommt.

- - - - - - -

Sicher ist so am Schluss, dass secondSmallest nicht überschrieben ist.

- - - - - - -

Trugschluss! Ist mit dem Letztfall ein smallest gegeben, wird dieser in secondSmallest gespeichert und bleibt erhalten. Ausnahme um Letztfall also erweitern. Als while() unter solchen Konditionen z.B.:

int[] arr;

int i=0;

while (i!=(arr.length()-1) && arr[i] < smallest) ...

Dies schlösse den Letztfall dann bereits aus. Wir führen allerdings einen Objektvergleich aus und keinen mathematischen. Besser wäre statt != also <= für die Integer nähere Betrachtung. Die length()-Funktion ist zudem eher String typisch und wird vererbt, bezieht sich intern für diesen Fall selber dann wohl auf Length. (Vgl. Vector mit size()-Funktion) Es gibt allerdings auch die Ersetzung von length() zu .length, wenn ich mich recht erinnere. arr.length könnte danach auch stimmen bzw. arr.LENGTH.

0
WitchHunter0815  31.07.2020, 16:09
@wooghie78

Es gibt in C# keine Length-Funktion, die hieße dann Length(), heißt aber Count() und kommt über den Namespace Linq erst hinzu. Jedoch hat ein Array eine length Eigenschaft, die hier genutzt wird. Und ich denke, wenn du dir einmal Blatt und Papier nimmst und das hier durchspielst, wirst du zu dem Ergebnis kommen, dass diese Variante stimmt.

Du sagst smallest ist mir egal - da stimme in Bezug auf das Ergebnis zu, aber nicht in Bezug auf die Notwendigkeit, diesen Wert zu kennen um zu Berechnen / Prüfen.

Anders gesagt, vergibst du smallest nur neu nach vorhergehender Feststellung von secondSmallest, da in der Schleife noch die Möglichkeit einer weiteren Prüfung anstehen könnte. Prinzipiell ist dir smallest jedoch egal.

Das ist falsch, denn wenn der Wert < smallest ist, dann muss der Wert, der vorher smallest war nun secondsmallest sein, ansonsten könnte aber der Fall eintreten, dass der Wert kleiner ist als secondsmallest, nicht jedoch kleiner als smallest, ergo muss die else if greifen.

0
wooghie78  31.07.2020, 16:37
@WitchHunter0815

Das Problem an ANSI C ist es, dass es Begrifflichkeiten vertauscht, so heißt das übliche Array (also Feld), wie man es aus Java kennt, dort bereits Vektor.

Das rührt daher, da man in C später viel mit Zeigern - aufgrund damit verbundener Zügigkeit - zu arbeiten hat und Vektor ebenfalls als Begriff für Zeiger selber gilt.

In Java ist der Vektor dagegen definiert, als ein unendliches Feld, in welchem man Objekte Speichern darf. Typen darin, sind prinzipiell egal, solange in Objektform. Man arbeitet im Gegensatz nicht mit .length() sondern mit .size().

C ist aus PHP erzeugt, dort findet man allerdings sämtliche von Java her bereits bekannten Funktionen wie length(), auch das eigentlich bekannte Array, als dem wichtigsten, anfänglichen Datentyp. Das also zunächst in den entsprechendsten Handbüchern nachzulesen, ergibt vorab zu C ein besseres Verständnis.

Arbeitet man mit Python oder sonstigem, eigentlich C-basiertem, ist die Besonderheit daran, dass eine Kombination zu Java und seiner Objekt-Orientierung damit geschaffen wurde. Eclipse ist ein ähnlicher Fall. In solchen IDE's findet man daher alle Begrifflichkeiten wieder, dennoch gelten diese Umgebungen selber als eingeschränkt.

0
LiLGemmeck 
Fragesteller
 02.08.2020, 16:04
@WitchHunter0815

Habe es nun verstanden. Was eigentlich nur gefehlt hat, war bei mir secondSmallest = smallest; ---> in der einen if-Schleife

Bei dir habe ich jedoch einen Fehler bemerkt, denn die erste if-Schleife ist endlos. Denn die Länge des Arrays wird immer größer als 1 sein - da ändert sich nix dran xD

Trotzdem danke!

0
WitchHunter0815  02.08.2020, 17:25
@LiLGemmeck

Also, dann hast du das erste IF und die Bedeutung wohl nicht so ganz verstanden.
Wenn der Array nur ein Element haben sollte - was ja vorkommen kann, dann gibt es kein 2 größtes Element. Somit muss dann ein Fehler geworfen werden (else). Eigentlich müsste die Prüfung auf null noch hinzu, aber die habe ich mal vernachlässigt.

Und zur Therminologie: If ist keine Schleife, sondern eine Bedingung

if (ary?.Length > 1 ?? false)

das wäre die komplette Variante.

0
PWolff  31.07.2020, 15:46

Stimmt - wenn denn tatsächlich das kleinste Element gesucht ist, das größer ist als das kleinste Element des Arrays insgesamt.

1
nun macht der von mir rot markierte indexSmallest für mich keinerlei Sinn. Da der Wert eines Array-Elementes meistens nicht identisch ist mit dem Wert seiner Position im Array, müsste das ganze ja völlig wahllose Ergebnisse liefern.

Das sehe ich ganz genauso. Deshalb wundert es mich, dass die erste Variante überhaupt funktioniert. (Kannst du probeweise mal ein Array mit Werten ab 100.000 aufwärts prüfen? Oder ein Array von Strings?)

Im Allgemeinen ist es durchaus von Vorteil, den Index eines Elementes zu wissen, deshalb wundert es mich nicht, dass eine Variable wie indexSmallest existiert - allerdings wundert mich, dass es keine Variable indexSecondSmallest gibt.

-----

Übrigens liefert diese Funktion ein anderes Ergebnis als z. B. die Excel-Funktion KKLEINSTE, die bei mehreren Elementen, die ebenso groß sind wie das kleinste, ebenfalls das kleinste Element zurückgeben. Beispiel:

=KKLEINSTE({5;4;5;4;7;4;8};2)

liefert als Ergebnis 4 zurück.

Woher ich das weiß:Berufserfahrung – Software-Entwickler
wooghie78  31.07.2020, 15:11

Es interessiert beim Array-Durchlauf wie oben beschrieben auch nur das erste Antreffen einer kleinsten, denn dann trifft die Kondition auf alle Weiteren der selben Art nicht mehr zu. Dein Beispiel wäre eher die Frage nach der Auffindung der Anzahl aller Kleinsten, hier also 4en, nämlich 3.

Was allerdings stört am obigem Beispiel von @LilGemmeck ist der fehlende Implementationskommentar. Zeilenweises besseres Lesen und verstehen.

0
PWolff  31.07.2020, 15:43
@wooghie78

KKLEINSTE liefert das kleinste, zweitkleinste, drittkleinste, ... Element eines Array zurück - je nach Inhalt des 2. Elements. Funktionalität wie in der Antwort von Erzesel.

0

Hi,

ich sehe da mehrere kleine Fehlerchen. Zunächst mal in der Frage des heran gehens...

Also du suchst den Zweitkleinsten. Klar, der erste if-clause ist richtig. Dann hat zu folgen:

  1. Speicherung in Variable a
  2. Speicherung in Variable b

Sobald das Array durchlaufen ist steht in b der richtige Wert, sofern nicht irgendwie überschrieben. Du läufst vermutlich einmal mehr durch. Sonst existiert zusätzlicher Sonderfall! Nicht nur den Erstfall, sondern auch der Letzfall wäre hier besonders zu betrachten.

Dennoch, auch zum Rest gibt es was zu bemängeln. C# hin oder her, für mich wirkt das wie Java, auch stilistisch. Dort benutzt man eher objekt-orientiert, die .length()-Funktion anstelle der statischen Variable .Length.

Zwei if-clauses zu schachteln ist auch nicht schön. Es gibt if/else if als Möglichkeit oder eben die else-clause. Außerdem Switch, als Alternative zu Punkt Eins, jedenfalls sofern schon bekannt gemacht.

Zu deinem Programm selber ist in obiger Erstausführung zu sagen, dass die zweite Kondition niemals zutreffen kann, auch für Folgedurchläufe, die darin gegebene binäre Und-Erweiterung als einer zusätzlich bindenden (einschränkenden) Kondition nützt daher nicht...

Man erkennt so, dass die hier eben aufgeführte Lösung dort noch nicht von dir erkannt wurde.

Der indexSmallest verwirrt Dich darüber hinaus selber bloß, du speicherst schließlich in der Objekt-Variablen. Bei C# dagegen bsp.w. innerhalb deiner definierten Member-Variablen zur Funktion. - Ansich dasselbe.

Der Index öffnet bloß die Speicherstelle im Array, an welcher du gerade deine Vergleiche anstellen möchtest. Die Behandlung in einer Schleife ist die beste und einfachste Möglichkeit. for() oder while().

Beachtest du auch das Zurückfallen der Schleifen-Durchläufe während der Beendigung, kommt es zu verschiedenen Instanz-Belegungen. In Java beachtet man solche eher nicht oder nutzt das Abbruch-Kriterium, welches mit solchen jeweils gegeben werden kann, sofern mehrere Belegungen stattfinden sollen. In diesem einfachen Fall, lohnt die Inkrementierung zu überdenken allerdings noch nicht.

Du benutzt eine Konsolen-Ausgabe anstelle der print()-Funktion des Systems wie bei Java, welche allerdings ebenfalls bloß statischen Anteil, in letztlicher main()-Funktion bildete. Die main() selber, kann dort nämlich bereits mit einem Argumentfeld belegt werden, dann hat man innerhalb solcher eigentlich bereits C-Konditionen, wenn es um nichts weiteres geht jedenfalls. Testet man gerade nicht, lässt man dieses Argumentfeld default-mäßig jedoch üblicherweise frei.

Für Konsolen-Ausgabe nutzt man alternativ zur print()- auch die echo()-Funktion.

Abgekürzt hat man bei uns das array außerdem eher mit arr, nicht mit ary. Testen zu lassen auf schwarzem Grund, ist nicht sinnvoll! Direkte Arbeit auf dem Server.

Woher ich das weiß:Studium / Ausbildung
regex9  01.08.2020, 00:31

1) Java-Arrays verfügen über keine length-Funktion. Dafür aber gibt es, wie in C#, ein Feld (length).

2) Worauf du in einigen Textabschnitten hinaus willst, ist mir ehrlich gesagt ein Rätsel. Zum Beispiel:

Du benutzt eine Konsolen-Ausgabe anstelle der print()-Funktion des Systems wie bei Java, welche allerdings ebenfalls bloß statischen Anteil, in letztlicher main()-Funktion bildete.

In Java erlangt man über ein statisches Feld der System-Klasse Zugriff auf den Ausgabekanal (oder über die Console-Klasse), in C# kann man es mit der Console-Klasse tun. Aber ein Vergleich zu Java ist hier doch ziemlich irrelevant?

Auch beim nachfolgenden Satz: In C# und in Java kann man über einen Parameter der Einstiegsmethoden die Argumente einlesen, die bei Programmstart über die Konsole mitgegeben wurden. Und?

3) In C# gibt es weder eine print- noch eine echo-Funktion. Das schließt sich bereits an den Bezeichnerschreibweisen aus.

0
wooghie78  05.08.2020, 00:11
@regex9

Hallo regex9,

  • ich beziehe mich damit auf meinen ersten Satz (Kommentar) zu seinem/ihrem Programmtext und will näher darauf eingehen, welche Fehler mir daran aufgefallen sind.
  • Nein, bei Java gibt es zwar auch statische vordefinierte Felder aus den üblichsten Parentklassen, aber ähnlich wie bei HTML nutzt man diese nicht wirklich direkt!
  • Ja, wenn man mit der Konsole als Maschienen bedienender Programmierer arbeitet, mag das sein. Dort in Kommando-Form, also ebenso statisch, das ist aber nicht der Punkt.
  • Ich sehe auch nicht auf welchen Satz du dich dabei beziehst, aber egal, vermutlich meinst du einen Vgl. zu der von mir beschriebenen main().

Der letztgenannte Punkt sieht dann in der startbaren Klasse etwa so aus:

public static void main (Str args[], ...) { ... }
  • In C# gibt es schon die üblichen Api-Funktionen zu print, du findest printf, fprintf, vprintf oder auch vfprintf, danach lässt sich jedoch gut googlen.
  • Man unterscheidet zwischen file-bezogenen Funktionen, welche einen file-stream als argument erwarten, um diesen (formatiert) ausgeben zu können oder den regulären, die dagegen eine Zeichen[ketten]-Konstante erwarten.
0
regex9  05.08.2020, 00:45
@wooghie78

1) Bevor du Antworten zu C#-Fragen schreibst und Fehler korrigieren möchtest, solltest du wissen, dass das eine komplett andere Sprache als C ist. Lässt sich auch gut googlen. 😐

2) HTML besitzt keine Klassen. Ist ja auch keine Programmiersprache. Wieso du anhand dieser Sprache irgendwas an der Klassenstruktur in Java andeuten möchtest - keine Ahnung.

In Java erlangt man jedenfalls über ein statisches Feld der System-Klasse Zugriff auf den Ausgabekanal:

System.out.print("Hello"); // out = static field

Das out-Feld wird direkt benutzt. Andernfalls könnte print nicht aufgerufen werden.

0

...und warum sortiert Du nicht einfach das Array und greifst den kleinsten Wert ab.?

using System;
					
public class Program
{
	public static void Main()
	{
		int[] numbers = { 2, 1, 4, 3 };

		Array.Sort(numbers);
        Console.WriteLine(numbers[0]);
        Console.WriteLine(numbers[1]);
	 
	}
}

https://docs.microsoft.com/de-de/dotnet/api/system.array.sort?view=netcore-3.1

https://www.csharp-examples.net/sort-array/

WitchHunter0815  31.07.2020, 14:51

Ich gehe davon aus, dass er es "zu Fuß" machen soll ...

2
PWolff  31.07.2020, 15:43

Sortieren ist teuer.

(Obwohl wir hier wohl nur eine Schülerübung haben, und dann gilt der Kommentar von WitchHunter0815.)

2
Oder ist meine (untere) Variante eventuell fehlerbehaftet?

Deine Variante liefert zum Beispiel für das Eingabearray [1, 2, 2, 2] ein falsches Ergebnis. Den oberen Code habe ich jetzt nicht getestet, aber der sollte das gleiche Problem haben, du hast auch recht - die Index-Variable ist sinnlos.