Rolf B: Dann eben so ...

Beitrag lesen

Hallo Raketenwilli,

nach meiner Grundsozialisierung in Vomhirninsgerätingen hatte ich noch eine Fortbildung in Cleanercodenhausen...

  • Ich würde needles nicht false als Defaultparameter geben. Lässt man diesen Parameter vortümlich oder irrsätzlich weg, kriegt man auf die Finger, weil der Parameter false sei. Besser fände ich
   if (arguments.length < 2) {
      throw new Error("CharCounter needs haystack and needles to do something useful");
   }
   if ('string' !== typeof haystack) {
      throw new Error("Haystack must be a string");
   }
   // alternativ
   if (!haystack || !(haystack.split instanceof Function)) {
      throw new Error("Haystack must be splittable");
   }
  • Dein Hantieren mit Counter und Needles finde ich ebenfalls unnötig kompliziert. Du erwartest für die needles einen String mit den zu prüfenden Zeichen, oder ein Array aus den zu prüfenden Zeichen. Werriwell. Aber du machst es Dir dann äußerst schwer, das zu validieren. Mit verwirrenden Fehlermeldungen. Wenn ich Dir eine Zahl übergebe, maulst Du, dass an Position 0 im Array needles kein String stünde.

Warum nicht so:

   if ('string' == typeof needles) {
      needles = needles.split('');
   }
   else if (Array.isArray(needles)) {
      if (!needles.every(needle => ('string' == typeof needle) &&
                                  (needle.length == 1))) {
         throw new Error("Needle array must contain only strings of length 1");
      }
   }
   else {
      throw new Error("Needles must be a string or an array of characters");
   }

Okay, das Ignorieren von Nadeln der Länge 0 fehlt. Das Initialisieren des counter-Arrays wäre dann der Folgeschritt.

Das Sortieren der Nadeln würde ich weglassen. Grund: die Zeichen (), {} und [] sind im Unicode paarweise beieinander. Aber vielleicht möchte jemand eine spezifische Reihenfolge. Oder in irgendeiner Fremdsprache sind die Zeichen, die Pärchen bilden, nicht so schön als Codepoints angeordnet. Ich würde die Nadeln genau in der Reihenfolge belassen, in der sie übergeben werden und es ein Feature nennen. Wer eine bestimmte Reihenfolge will, soll sie vorsortieren. DOT[1].

Im Sinne des DOT-Prinzips könnte man sogar darüber nachdenken, die Schnittstelle der Funktion zu verschlanken und die Überladung von needles mit string und Array wegzulassen. Lass als needles nur einen String zu. Wer ein Array hat, soll es flugs joinen, das ist nicht viel Arbeit.

<denk>Man KÖNNTE es aber auch so machen, dass man haystack und needles nicht auf string prüft, sondern ein iterierbares Objekt erwartet. Das kann man bspw. mit if (needles[Symbol.iterator]) testen. Die Strafe dafür ist dann, dass man jeden Wert der Iteration darauf prüfen muss, ob er ein String der Länge 1 ist. Hm. Nö. Gefällt mir nicht.</denk>

Wenn needles ein String sind, kannst Du mit indexOf schauen, ob das aktuelle Zeichen in haystack eins ist, das Du zählen möchstest. Aber - LOL - wenn sie ein Array sind, geht das genauso. Aber Du sparst Dir die Analyse auf einen String aus einem Zeichen pro Arrayeintrag. Das würde ich als Problem Anderer Leute deklarieren.

Den haystack mit split('').foreach(...) zu durchlaufen - kann man machen. Aber man könnte auch die for..of Schleife nutzen - der IE ist schließlich zu glorreicher Irrelevanz erhoben worden…

Für die log-Schleife (deren Existenz ebenfalls auf dem DOT-Altar geopfert werden sollte), bietet sich dann noch ein Template-String in Backticks an.

   let counter = {};
   for (let pin of needles) {
      counter[pin] = 0;
   }

   for (let straw of haystack) {
      if (needles.indexOf(straw) >= 0) {
         counter[straw]++;
      }
   }

   if (log) {
      for (let pin of needles) {
         console.log(`Char »${pin}« occurs ${counter[pin]} times`);
      }
   }

Die Idee mit dem Iterator sähe so aus:

   if (!(haystack[Symbol.iterator] instanceof Function) ||
       !(needles[Symbol.iterator] instanceof Function)) {
      throw new Error("haystack and needles must be iterable");
   }
   let counter = {};
   for (let pin of needles) {
      if ('string' != typeof pin || pin.length != 1) {
         throw new Error(...);
      }
      counter[pin] = 0;
   }
   for (let straw of haystack) {
      if ('string' != typeof pin || pin.length != 1) {
         throw new Error(...);
      }
      let c = counter[straw];
      if (c != undefined)
         counter[straw] = c+1;
      }
   }

Aber diese Prüfungen dürften Laufzeitstrafe bringen. Deswegen schmeckt mir das nicht so. Es sei denn, man definiert das als Feature - und sagt: Das ist ein generischer Counter. Wer in haystack und needles etwas drin hat, was kein String der Länge 1 ist - na gut, der zählt dann halt das. Und damit sind die Prüfungen nicht nur unnötig, sondern sogar störend.

Rolf

--
sumpsi - posui - obstruxi

  1. Do One Thing ↩︎