warum verwenden die meisten von uns 'i' als schleifenzählervariable?
<p>hat jemand darüber nachgedacht, warum so viele von uns dasselbe muster mit denselben variablennamen wiederholen?</p><pre class="lang-c prettyprint-override"><code>for (int i = 0; i &lt; foo; i++) { // ... } </code></pre><p>es scheint, dass der meiste code, den ich mir jemals angesehen habe, <code>i</code>, <code>j</code>, <code>k</code> usw. als iterationsvariablen verwendet.</p><p>ich nehme an, ich habe das irgendwo aufgegriffen, aber ich frage mich, warum dies in der softwareentwicklung so weit verbreitet ist. ist es etwas, das wir alle von c aufgegriffen haben oder so?</p><p>nur ein juckreiz, den ich seit einiger zeit im hinterkopf hatte.</p>
<p><code>i</code> und <code>j</code> werden in der regel seit geraumer zeit als indizes in einigen mathematischen bereichen verwendet (z. b. sehen sie selbst in artikeln, die älter sind als höhere sprachen, häufig dinge wie "x.<sub>ich, j</sub>", besonders in sachen wie einer summe).</p><p>als sie fortran entwarfen, beschlossen sie (anscheinend), dasselbe zuzulassen, sodass alle variablen, die mit "i" bis "n" beginnen, standardmäßig auf ganzzahl und alle anderen auf real (gleitkomma) eingestellt sind. für diejenigen, die es verpasst haben, ist dies die quelle des alten witzes "gott ist real (sofern nicht als ganzzahl deklariert)".</p><p>die meisten menschen scheinen wenig grund gesehen zu haben, dies zu ändern. es ist weithin bekannt und verstanden und ziemlich prägnant. hin und wieder sieht man etwas, das von einem psychotiker geschrieben wurde, der glaubt, dass etwas wie ein echter vorteil ist:</p><pre class="lang-c prettyprint-override"><code>for (int outer\_index\_variable=0; outer\_index\_variable &lt; 10; outer\_index\_variable++) for (int inner\_index\_variable=0; inner\_index\_variable &lt; 10; inner\_index\_variable++) x[outer\_index\_variable][inner\_index\_variable] = 0; </code></pre><p>zum glück ist dies jedoch ziemlich selten, und die meisten styleguides weisen jetzt darauf hin, dass lange, beschreibende variablennamen <em>können</em> nützlich sein, sie <em>nicht</em> sie immer benötigen, insbesondere für etwas dies ist der fall, wenn der gültigkeitsbereich der variablen nur ein oder zwei codezeilen umfasst.</p>
<p>c hat den vorteil, dass es eine relativ <strong> <em> kleine sprache</em> </strong> ist, was es <strong> macht ) <em> einfach einen c-compiler zu implementieren</em> </strong> (während ein c++ - compiler ein monster zum schreiben ist), und macht es <strong> = <em> leichter die sprache zu lernen</em> </strong>. siehe auch <a href="https://www.tiobe.com/tiobe-index/">tiobe-index</a> , wonach c etwas vor c++ liegt.</p><p>in (imo) abnehmender reihenfolge der rechtfertigung wird c immer noch häufig verwendet</p><ul> <li> <p>eingebettetes zeug<br> es ist viel einfacher, einen c-compiler auf eine kleine plattform zu portieren, als einen c++ - compiler zu portieren. außerdem behaupten c-befürworter, dass c++ "hinter ihrem rücken zu viel tut". allerdings imo das ist fud.</p> </li> <li> <p>systemprogrammierung<br> auch dies ist normalerweise auf die behauptung zurückzuführen, dass es einfacher ist, "zu wissen, was der compiler tut". viele eingebettete programme würden jedoch beispielsweise von vorlagen und anderen c++ - schlüsselfunktionen profitieren.</p> </li> <li> <p>quelloffene software<br> das ist jedoch meistens ein einstellungsproblem: oss hat c immer c++ vorgezogen (während es in großen teilen der branche das gegenteil ist). torvalds irrationaler hass könnte tatsächlich der wichtigste grund dafür sein <em> unter linux</em>.</p> </li> </ul> <p>es ist wahrscheinlich ein versuch, passwörter zu entmutigen, die zu gängigen formaten oder zeichenmasken passen. wenn für eine kennwortrichtlinie die verwendung einer nummer erforderlich ist, setzen viele personen ihre nummer am ende eines wortes oder von wörtern. hier einige beispiele aus unternehmensumgebungen:</p><ul> <li> <a href="http://passwordresearch.com/stats/statistic397.html">netspi top password masks für 2015</a> </li> <li> <a href="http://passwordresearch.com/stats/statistic376.html">2015 trustwave global security report - kennwortmasken</a> </li> </ul><p>angreifer mögen diese benutzergewohnheit, weil sie das knacken oder erraten von hybrid-passwörtern erleichtert. sie können sich darauf konzentrieren, wortlisten mit am ende hinzugefügten zahlen zu kombinieren, anstatt einen zeitaufwändigeren brute-force-ansatz zu wählen.</p><p>einige organisationen implementieren eine solche richtlinie, um die sicherheit zu verbessern, indem benutzer dazu gebracht werden, ihre nummern einzugeben. dies ist ein weniger vorhersehbarer ort. es hört sich so an, als würden sie dies in ihrer situation nicht mit einer anderen komplexitätsprüfung kombinieren und stattdessen alle passwörter ablehnen, die mit einer zahl enden, unabhängig davon, wie zufällig sie ansonsten sind. das ist keine sehr gute möglichkeit, diese art der überprüfung zu implementieren, aber sie sind mit diesem ansatz nicht allein.</p> <p>es wird in den stapel-auflösetabellen verwendet, die sie zum beispiel in der assembly-ausgabe von <a href="https://stackoverflow.com/questions/307610/how-do-exceptions-work-behind-the-scenes-in-c#307716">meine antwort auf eine andere frage</a> sehen können. wie in dieser antwort erwähnt, wird ihre verwendung durch <a href="https://itanium-cxx-abi.github.io/cxx-abi">itanium c++ abi</a> definiert, wobei sie <a href="https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html#base-personality">personality routine</a> genannt wird.</p><p>der grund, warum es "funktioniert", indem es als globaler null-leerzeiger definiert wird, ist wahrscheinlich, dass nichts eine ausnahme auslöst. wenn etwas versucht, eine ausnahme auszulösen, werden sie feststellen, dass es sich schlecht benimmt.</p><p>wenn keine ausnahmen verwendet werden, können sie diese natürlich mit <code>-fno-exceptions</code> deaktivieren (und wenn rtti nicht verwendet wird, können sie auch <code>-fno-rtti</code> hinzufügen). wenn sie sie verwenden, müssen sie (wie andere bereits erwähnte antworten) mit <code>g++</code> anstelle von <code>gcc</code> verknüpfen, wodurch <code>-lstdc++</code> für sie hinzugefügt wird.</p> <p>ich würde folgendes überlegen:</p><ul> <li>möchten sie, dass ihr code aus sprachen verwendet wird, die optionale parameter nicht unterstützen? wenn ja, ziehen sie die überlastungen in betracht.</li> <li>hast du irgendwelche mitglieder in deinem team, die freiwillige parameter gewaltsam ablehnen? (manchmal ist es einfacher, mit einer entscheidung zu leben, die sie nicht mögen, als den fall zu diskutieren.)</li> <li>sind sie zuversichtlich, dass sich ihre standardwerte nicht zwischen builds ihres codes ändern, oder wenn dies der fall ist, werden ihre anrufer damit einverstanden sein?</li> </ul><p>ich habe nicht überprüft, wie die standardeinstellungen funktionieren, aber ich würde davon ausgehen, dass die standardwerte in den aufrufenden code eingebettet werden, ähnlich wie verweise auf <code>const</code>-felder. das ist normalerweise in ordnung - änderungen an einem standardwert sind sowieso ziemlich wichtig - aber das sind die dinge, die zu beachten sind.</p> <p>sie sollten versuchen, schleifen generell zu vermeiden. sie sind normalerweise weniger effizient als satzbasierte lösungen und weniger lesbar.</p><p>das folgende sollte ziemlich effizient sein.</p><p>dies gilt umso mehr, wenn die spalten name und weight im index <code>include-</code> d sein könnten, um die schlüsselsuche zu vermeiden.</p><p>es kann den eindeutigen index in der reihenfolge <code>turn</code> scannen und die laufende summe der spalte <code>weight</code> berechnen. verwenden sie dann <code>lead</code> mit denselben ordnungskriterien, um die laufende summe zu ermitteln die nächste reihe wird sein.</p><p>sobald die erste zeile gefunden wird, in der diese 1000 überschreitet oder <code>null</code> ist (was anzeigt, dass keine nächste zeile vorhanden ist), kann der scan gestoppt werden.</p><pre><code>with t1 as (select *, sum(weight) over (order by turn rows unbounded preceding) as cume\_weight from [dbo].[line]), t2 as (select lead(cume\_weight) over (order by turn) as next\_cume\_weight, * from t1) select top 1 name from t2 where next\_cume\_weight &gt; 1000 or next\_cume\_weight is null order by turn </code></pre><h1>ausführungsplan</h1><p> <a href="https://i.stack.imgur.com/gb1mw.png">(<img src="https://i.stack.imgur.com/gb1mw.png" alt="enter image description here"></a> </p><p>in der praxis scheint es ein paar zeilen vor dem unbedingt erforderlichen zu lesen - es sieht so aus, als würde jedes fenster-spool/stream-aggregat-paar zwei zusätzliche zeilen lesen.</p><p>für die beispieldaten in der frage müssten im idealfall nur zwei zeilen aus dem index-scan gelesen werden, in wirklichkeit werden jedoch 6 zeilen gelesen. dies ist jedoch kein wesentliches effizienzproblem und verschlechtert sich nicht, wenn der tabelle weitere zeilen hinzugefügt werden (wie in) <a href="https://dbfiddle.uk/?rdbms=sqlserver\_2017&amp;fiddle=892e6bb7c1af912413b01d05e606a98a">diese demo</a> )</p><p>für diejenigen, die an dieser ausgabe interessiert sind, wird unten ein bild mit den von jedem operator ausgegebenen zeilen (wie durch das erweiterte ereignis <code>query\_trace\_column\_values</code> gezeigt) angezeigt. die zeilen werden in der reihenfolge <code>row\_id</code> ausgegeben (beginnend mit <code>47</code> für die erste zeile, die vom index-scan gelesen wurde und bei <code>113</code> für <code>top</code> endet)</p><p>klicken sie auf das bild unten, um es zu vergrößern, oder sehen sie alternativ <a href="https://imgur.com/a/c7npqqh">die animierte version, um den ablauf einfacher zu verfolgen</a> .</p><p>anhalten der animation an dem punkt, an dem das rechte stream-aggregat seine erste zeile ausgegeben hat (für gary - turn = 1). es scheint offensichtlich, dass es darauf gewartet hat, seine erste zeile mit einem anderen windowcount zu erhalten (für jo - turn = 2). und die fensterspule gibt die erste "jo" -zeile erst frei, wenn sie die nächste zeile mit einem anderen <code>turn</code> gelesen hat (für thomas - turn = 3)</p><p>die fensterspule und das stream-aggregat bewirken also, dass eine zusätzliche zeile gelesen wird, und es gibt vier davon im plan - daher 4 zusätzliche zeilen.</p><p> <a href="https://i.stack.imgur.com/cwllc.jpg">(<img src="https://i.stack.imgur.com/cwllc.jpg" alt="enter image description here"></a> </p><p>es folgt eine erläuterung der oben gezeigten spalten (basierend auf info <a href="https://www.microsoft.com/en-us/p/microsoft-sql-server-2012-high-performance-t-sql-using-window-functions/fgqpf3h0qlch">hier</a> )</p><ul> <li><strong> knotenname: index-scan, knoten-id: 15, spaltenname: id </strong> basistabellenspalte, die vom index abgedeckt wird</li> <li><strong> knotenname: index-scan, knoten-id: 15, spaltenname: drehen sie die basistabellenspalte </strong>, die vom index abgedeckt wird</li> <li><strong> nodename: clustered index seek, nodeid: 17, columnname: gewicht </strong> basistabellenspalte, die aus der suche abgerufen wurde</li> <li><strong> nodename: clustered index seek, nodeid: 17, columnname: name </strong> basistabellenspalte, die aus der suche abgerufen wurde</li> <li><strong> nodename: segment, nodeid: 13, columnname: segment1010 </strong> gibt 1 am anfang einer neuen gruppe zurück oder andernfalls null. da kein <code>partition by</code> in <code>sum</code> vorhanden ist, erhält nur die erste zeile 1</li> <li><strong> nodename: sequenzprojekt, nodeid: 12, columnname: rownumber1009 </strong> <code>row\_number()</code> innerhalb der durch das segment1010-flag angegebenen gruppe. da sich alle zeilen in derselben gruppe befinden, werden ganze zahlen von 1 bis 6 aufgestiegen. wird in fällen wie <code>rows between 5 preceding and 2 following</code> zum filtern von zeilen mit rechten rahmen verwendet. (oder wie für <code>lead</code> später)</li> <li><strong> nodename: segment, nodeid: 11, columnname: segment1011 </strong> gibt 1 am anfang einer neuen gruppe zurück oder andernfalls null. da kein <code>partition by</code> in <code>sum</code> vorhanden ist, erhält nur die erste zeile 1 (wie segment1010).</li> <li><strong> nodename: window spool, nodeid: 10, columnname: windowcount1012 </strong> attribut, das zeilen gruppiert, die zu einem fensterrahmen gehören. diese fensterspule verwendet den fall "fast track" für <code>unbounded preceding</code>. wo es zwei zeilen pro quellzeile ausgibt. eins mit den kumulativen werten und eins mit den detailwerten. obwohl es keinen sichtbaren unterschied in den durch <code>query\_trace\_column\_values</code> offenbarten zeilen gibt, gehe ich davon aus, dass kumulative spalten in der realität vorhanden sind.</li> <li><strong> nodename: stream aggregate, nodeid: 9, columnname: expr1004 </strong> <code>count(*)</code> gruppiert nach windowcount1012 gemäß plan, aber tatsächlich eine laufende anzahl</li> <li><strong> nodename: stream aggregate, nodeid: 9, columnname: expr1005 </strong> <code>sum(weight)</code> gruppiert nach windowcount1012 gemäß plan, aber tatsächlich die laufende gewichtssumme (dh <code>cume\_weight</code>)</li> <li><strong> nodename: segment, nodeid: 7, columnname: expr1002 </strong> <code>case when [expr1004]=(0) then null else [expr1005] end</code> - sehen sie nicht, wie <code>count(*)</code> kann sei 0, also läuft immer die summe (<code>cume\_weight</code>)</li> <li><strong> knotenname: segment, knoten-id: 7, spaltenname: segment1013 </strong> nein <code>partition by</code> in <code>lead</code>, sodass die erste zeile 1 erhält. alle verbleibenden werden null</li> <li><strong> nodename: sequenzprojekt, nodeid: 6, columnname: rownumber1006 </strong> <code>row\_number()</code> innerhalb der durch das segment1013-flag angegebenen gruppe. da sich alle zeilen in derselben gruppe befinden, sind dies ganze zahlen von 1 bis 4</li> <li><strong> nodename: segment, nodeid: 4, columnname: bottomrownumber1008 </strong> rownumber1006 + 1, da <code>lead</code> die nächste zeile erfordert</li> <li><strong> nodename: segment, nodeid: 4, columnname: toprownumber1007 </strong> rownumber1006 + 1, da <code>lead</code> die nächste zeile erfordert</li> <li><strong> knotenname: segment, knoten-id: 4, spaltenname: segment1014 </strong> nein <code>partition by</code> in <code>lead</code>, sodass die erste zeile 1 erhält. alle verbleibenden werden null</li> <li><strong> nodename: window spool, nodeid: 3, columnname: windowcount1015 </strong> attribut, das zeilen, die zu einem fensterrahmen gehören, unter verwendung der vorherigen zeilennummern gruppiert. der fensterrahmen für <code>lead</code> hat maximal 2 zeilen (die aktuelle und die nächste)</li> <li><strong> nodename: stream aggregate, nodeid: 2, columnname: expr1003 </strong> <code>last\_value([expr1002])</code> für <code>lead(cume\_weight)</code></li> </ul> <p>eine sache, die wir dort getan haben, wo ich arbeite, ist eine "speicher" -dienst-api. grundsätzlich post ein json-objekt an den service, und es gibt eine uuid zurück. sie senden die uuid als abfrageparameter bei jedem nachfolgenden api-aufruf und es werden die parameter/daten aus dem speicher abgerufen dies ist besonders praktisch, wenn sie mehrere anrufe mit denselben daten tätigen, da sie diese nur einmal senden müssen.</p> <p>zunächst einmal herzlichen glückwunsch zum "sehen des lichts". sie haben die software-welt zu einem besseren ort gemacht, indem sie ihren horizont erweitert haben.</p><p>zweitens gibt es ehrlich gesagt keine möglichkeit, dass ein professor, der die funktionale programmierung nicht versteht, etwas nützliches über ihren code sagen kann, außer banalen kommentaren wie "die einrückung sieht aus". dies ist in einem webentwicklungskurs nicht so überraschend, da die meisten webentwicklungen mit html/css/javascript durchgeführt werden. abhängig davon, wie sehr sie sich tatsächlich für das erlernen der webentwicklung interessieren, möchten sie möglicherweise anstrengungen unternehmen, um die werkzeuge zu erlernen, die ihr professor lehrt (auch wenn dies schmerzhaft sein mag - ich weiß aus erfahrung).</p><p>um die angegebene frage zu beantworten: wenn ihr imperativcode eine schleife verwendet, ist ihr funktionscode wahrscheinlich rekursiv.</p><pre><code>(* raises x to the power of y *) fun pow (x: real) (y: int) : real = if y = 1 then x else x * (pow x (y-1)) </code></pre><p>beachten sie, dass dieser algorithmus tatsächlich mehr oder weniger mit dem imperativen code identisch ist. tatsächlich könnte man die obige schleife als syntaktischen zucker für iterative rekursive prozesse betrachten.</p><p>nebenbei bemerkt, es ist weder in ihrem imperativ- noch in ihrem funktionscode ein wert von <code>z</code> erforderlich. sie sollten ihre imperative funktion so geschrieben haben:</p><pre><code>def pow(x, y): var ret = 1 for (i = 0; i &lt; y; i++) ret = ret * x return ret </code></pre><p>anstatt die bedeutung der variablen <code>x</code> zu ändern.</p> <p>was sie erstellen möchten, ist eine <a href="http://en.wikipedia.org/wiki/domain-specific\_language">domänenspezifische sprache</a> . das grundprinzip dieser art von (programmier-) sprache lautet: halten sie die syntax so einfach wie möglich, während sich einfach auf "vom menschen lesbar" bezieht, indem sie alle nicht benötigten funktionen entfernen.</p><h2>schwierigkeiten der c-syntax</h2><p>was macht c-syntax schwer zu schreiben:</p><ul> <li>fehlendes nachlaufen; ich habe viele anfänger gesehen, die auf diesem fluch waren.</li> <li>fehlend} oder).</li> <li>das konzept der zeiger <em> (sie werden diesen wahrscheinlich nicht brauchen) </em></li> <li>variable bereiche</li> <li>copy-by-value vs. referenzen</li> </ul><p>wenn sie eine kleine teilmenge der sprachfunktionen verwenden, ist der code sowohl leichter zu lesen als auch zu schreiben (sofern er konsistent ist).</p><h2>beispiel</h2><p>angenommen, der code muss ausdrücken, dass prozess a von prozess b abhängig ist.</p><pre><code>process a = "cook something"; process b = "go shopping."; depends\_on(a, b); </code></pre><p>oder:</p><pre><code>cook something &lt;- go shopping </code></pre><p>im zweiten beispiel muss der "codierer" nicht einmal das konzept der parameter kennen!</p><h2>technische komplexität beeinflusst die benutzerfreundlichkeit</h2><p>was am ende mindestens genauso wichtig sein kann: eine anständige kompilierungs-/debugging-umgebung, fehlermeldungen, die zur lösung des eigentlichen problems beitragen usw. aufgrund der technischen schwierigkeiten beim parsen von c gibt der compiler häufig nur schwache fehler aus im zusammenhang mit der wahren ursache. auch hier hilft eine einfache syntax.</p> Jython Compiler bietet nicht viel Optimierungs Entscheidungen. Da jedoch die Java Virtual Machine (Java) und vielleicht Compiler (javac) im Backend oder zur Laufzeit aufgerufen zu werden, sollten Sie einen Blick auf sie nehmen.


Java hat unterschiedlichen Laufzeitschalter je nach verwenden, ob Sie es als Server-Prozess starten wollen, Client-Prozess, etc. Sie können auch, wie vielen Speicher sagen zuzuteilen. Ist die Anzahl der Ziffern immer gleich lang?


Dann kannst du als benutzerdefiniertes Format  verwenden.