foreach mit Index (Laufvariable)
-
Dravere schrieb:
Ich hätte da mal eine andere Frage: Wozu brauchst du diesen Index regelmässig? Kannst du da Beispiele nennen?
GrüssliIch komme immer wieder in die Situation, dass ich gegen die IEnumerable-Schnittstelle programmiere und mit foreach darüber iteriere. Im Laufe der Entwicklung sich aber zeigt, dass ein Index notwendig ist. Zum Beispiel für IDs oder andere Berechnungen. Bisher hab ich dann oft mit der Schnittstellenprogrammierung gebrochen und auf Lists oder andere konkrete, indizierbare Typen zurück gegriffen. Oder eine Laufvariable außerhalb des foreach-scope eingeführt. Alles nicht das Wahre.
ToIndexedEnumerable() gefällt mir jetzt sehr gut (auch bei der Eingabe: ".ToI" <Tab>. Null Aufwand). Der umfangreiche Code hat mich anfangs noch gestört aber mit ein wenig Inspiration von diesem Thread hat sich das auf ein akzeptables Niveau reduziert. Ich denke mal am Montag fließt das in den Produktivcode ein
Es gibt noch zwei Sonderfälle einer Iteration: Das erste und das letzte Element müssen häufig gesondert von den restlichen Elementen einer Enumeration behandelt werden. Das erste Element kann mit dem Code jetzt abgefangen werden. Der Index steht ja zur Verfügung und man kennt den Startindex. Für das letzte Element hab ich noch keine elegante und performante Lösung. Count() von LINQ ist inakzeptabel wegen dem linearen Aufwand.
Mal schauen....
-
Count() von LINQ ist inakzeptabel wegen dem linearen Aufwand.
Huh? Hat es das auch wenn darunter eine Collection liegt die ihre größte in O(1) weiß? Meiner einer muss am Montag sein Projekt durchsuchen. Hab bestimmt Count() verwendet...
MfG SideWinder
-
Wenn Count() gegen IEnumerable aufgerufen wird, hat es linearen Aufwand. Unabhängig von der konkreten Klasse dahinter.
EDIT: Jetzt komme ich auch ins Schleudern. Wurde Count() für z.B. List überschrieben?
-
SideWinder schrieb:
Meiner einer muss am Montag sein Projekt durchsuchen. Hab bestimmt Count() verwendet...
Tja. Du bist halt eine Flasche, sagen manche Anfänger. Deine Verfehlungen haben bestimmt mindestens 0 Tage Arbeitszeit gekostet.
Da bin ich sicher. Würdest Du in großen Projekten arbeiten, wäre es sogar fünfmal so viel.
-
*nehme mal Sarkasmus an, bin schon etwas müde*
Ich sag ja nicht, dass ich da mit so großen Datenmengen arbeiten würde, als dass es einen Unterschied machen würde, aber es sieht halt dann nicht gut aus. Und ein kleines "Find in solution" tut nun auch nicht weh
MfG SideWinder
-
volkard schrieb:
Tja. Du bist halt eine Flasche, sagen manche Anfänger.
Hast Du irgendein persönliches Problem mit mir?
-
µ schrieb:
volkard schrieb:
Tja. Du bist halt eine Flasche, sagen manche Anfänger.
Hast Du irgendein persönliches Problem mit mir?
Nein, DU bist für mich ein Profi im nichteigenlichen (im eigentlichen vielleicht auch, das kann ich aber kaum wissen) Sinne. Du bist mir sehr oft mit einer Expertise positiv aufgefallen.
-
Dravere schrieb:
David W schrieb:
Im übrigen, "Sequenz kopieren"? Wenn du eine IEnumerable hast daraus eine Liste machst werden auch nur die Referenzen geholt und gesammelt in einer Liste angeboten. Die Leistung dürfte zu vernachlässigen sein, außer eventuell das alle Referenzen direkt aufgelöst werden.
Mit solchen Aussagen wäre ich vorsichtig. Vor allem wenn es um allgemeine Aussagen geht. Man sollte nie vergessen, dass es auch Linq to SQL gibt. Ein
IEnumerable
könnte plötzlich Abfragen in einer Datenbank machen. DasToList
führt dann alle Abfragen durch, womöglich ungewollt.Grüssli
Aber wenn ich eh mit foreach eine Iteration über die gesamte Menge laufen lasse, spielt das dann aber auch keine Rolle mehr. Außer das ein paar Referenzen kopierte werden, wie David oben angemerkt hat. Wenn man in seiner foreach Schleife eine Abbruchbedingung drinnen hat, dann ist mir schon klar, das ToList nicht immer elegant ist
-
µ schrieb:
EDIT: Jetzt komme ich auch ins Schleudern. Wurde Count() für z.B. List überschrieben?
Geht das überhaupt? Wird für Extension Methods ein Dispatch gemacht?
µ schrieb:
Es gibt noch zwei Sonderfälle einer Iteration: Das erste und das letzte Element müssen häufig gesondert von den restlichen Elementen einer Enumeration behandelt werden.
Ich habs glaub ich schonmal gesagt: Die eigentliche Warze ist foreach. Ein Statement, das genau dann elegante Lösungen ermöglicht, wenn man genau das machen will, was sich der Designer gedacht hat. Kleine Abweichungen: Pech gehabt!
(Vielleicht ist es auch meine Lisp-Vergangenheit. Lernt bloß nie Lisp, dann ist alles frustrierend.)
-
Es gibt eine Sprache die innerhalb von foreach automatisch eine Variable namens $ zur Verfügung stellt die als Laufvariable dient. Das ist wunderschön *mir für C# wünsch* *auch wenn mich Bashar knüppelt*
MfG SideWinder
-
Bashar schrieb:
µ schrieb:
EDIT: Jetzt komme ich auch ins Schleudern. Wurde Count() für z.B. List überschrieben?
Geht das überhaupt? Wird für Extension Methods ein Dispatch gemacht?
Sieht nicht so aus, aber es gibt offenbar Wege: http://www.codeproject.com/KB/tips/PolymorphExtensionVisitor.aspx
*volkards Posting nicht ganz versteh, mir jemand erklären will?*
MfG SideWinder
-
Noob3453 schrieb:
Aber wenn ich eh mit foreach eine Iteration über die gesamte Menge laufen lasse, spielt das dann aber auch keine Rolle mehr. Außer das ein paar Referenzen kopierte werden, wie David oben angemerkt hat. Wenn man in seiner foreach Schleife eine Abbruchbedingung drinnen hat, dann ist mir schon klar, das ToList nicht immer elegant ist
Nicht nur wegen der Abbruchbedingung. Es können auch Nebeneffekte erst in der Schleife auftreten, welche das Ergebnis verändern würden. Wie gesagt, einfach mit Vorsicht behandeln.
@μ,
Empfinde ich seltsam, dass du immer wieder einen Index brauchst. Deshalb habe ich nämlich nachgefragt. Bei der Antwort von Bashar auf meine Frage, sieht man, dass er es eher in Ausnahmefällen benötigt. Bei dir scheint das ja eher ganz normal zu sein.
Ich frage mich daher, ob du nicht irgendetwas falsch machst? Vielleicht solltest du deine Design etwas überdenken? Wieso genau brauchst du immer wieder einen Index? Könnte man es anders lösen? Den Index als ID zu nehmen, halte ich übrigens für extrem gefährlich. Sowas sollte man nur temporär machen. Aber wieso überhaupt? Du hast ja sowieso nur einIEnumerable
, wieso brauchst du dann eine ID? Was wäre die Alternative zu dieser ID? usw.@all,
LinqCount
verwendetICollection<T>.Count
, sofern dies zur Verfügung steht:
http://msdn.microsoft.com/en-us/library/bb338038.aspxMSDN schrieb:
Remarks
If the type of source implementsICollection<T>
, that implementation is used to obtain the count of elements. Otherwise, this method determines the count.Grüssli
-
Der Index wird eigentlich total selten gebraucht, und dort wo es gebraucht wird kann man ja mal schauen ob eine ToList() nicht tatsächlich schon reichen würde ("mit vorsicht behandeln").
Es wird praktisch nie vorkommen das man ein index braucht und nicht mit ToList arbeiten kann wegen Seiteneffekten.
Und selbst dann kann man mit einem Index arbeiten der außerhalb der for definiert ist, wenn die Lebensdauer stört der kann ja ein leeren Scope block definieren."foreach (var pair in myList.ToIndexedEnumerable())" ist zwar sehr elegant aber nicht so lesbar, da es zum einen nicht in der MSDN steht. Das man den Namespace der Extension Method kennen muss. Wissen das es da ist, und zu guter letzt wissen das ToIndexedEnumerable eine KeyValuePair Liste zurückgibt.
Eleganz hin oder her, Code wird öfter gelesen als geschrieben, also nimmt man das einfacherer.
Ich hatte erst letztens eine Mail von den CCD Jungs und da hieß es auch:Clean Code ist gut; aber eleganter Code ist noch besser. Oder?
In einem vieldiskutierten Blogartikel argumentiere ich dagegen. Mein Plädoyer gilt transparentem Code. Was er tut und wie er es tut, soll klar erkennbar sein. Code soll geradezu nakt vor dem lesenden Entwickler stehen. Details zu verbergen, mag in anderen Bereichen eine Tugend sein; in der Softwareentwicklung ist es Unverhülltheit.
Quelle: http://ralfw.blogspot.com/2011/06/porno-statt-erotik-in-der.html
-
Dravere schrieb:
David W schrieb:
Im übrigen, "Sequenz kopieren"? Wenn du eine IEnumerable hast daraus eine Liste machst werden auch nur die Referenzen geholt und gesammelt in einer Liste angeboten. Die Leistung dürfte zu vernachlässigen sein, außer eventuell das alle Referenzen direkt aufgelöst werden.
Mit solchen Aussagen wäre ich vorsichtig. Vor allem wenn es um allgemeine Aussagen geht. Man sollte nie vergessen, dass es auch Linq to SQL gibt. Ein
IEnumerable
könnte plötzlich Abfragen in einer Datenbank machen. DasToList
führt dann alle Abfragen durch, womöglich ungewollt.Grüssli
Noch eine Frage zu deinem Beispiel mit SQL. Wenn hinter einer Enumeration eine Datenbankabfrage steht, dann geschieht dies doch über sog. Proxy-Objekte. Ein Proxy wird aber erst aufgelöst, wenn auf eines der Properties zugegriffen wird. Ein ToList() würde doch dann nur die Referenz kopieren, aber nicht den Proxy auflösen.
-
Noob3453 schrieb:
Noch eine Frage zu deinem Beispiel mit SQL. Wenn hinter einer Enumeration eine Datenbankabfrage steht, dann geschieht dies doch über sog. Proxy-Objekte. Ein Proxy wird aber erst aufgelöst, wenn auf eines der Properties zugegriffen wird. Ein ToList() würde doch dann nur die Referenz kopieren, aber nicht den Proxy auflösen.
Nein, meistens ist der Proxy das
IEnumerator
Objekt. Dann wird die Abfrage mitMoveNext
ausgelöst. Das Problem ist wirklich, was sich eigentlich hinter demIEnumerator
versteckt, den man vomIEnumerable
bekommt.Grüssli
-
private void Foo(IEnumerable<string> bar) { for (int i = 0; i < bar.Count(); ++i) { var item = bar.ElementAt(i); } }
-
David W schrieb:
private void Foo(IEnumerable<string> bar) { for (int i = 0; i < bar.Count(); ++i) { var item = bar.ElementAt(i); } }
Quadratische Laufzeit.