Is My FizzBuzz Solution Terrible?

In this video we go through the most commonly raised issues about my earlier video regarding Tom Scott's FizzBuzz solution.
Previous video: • One Simple Trick to In...
bit-machine.co.uk/

Пікірлер: 336

  • @turgutbababalm9981
    @turgutbababalm99818 ай бұрын

    This one is worse. You failed by using VSCode and not vim and not using arc linux like a REAL programmer. You are also using javascript unlike a real developer who whispers directly into the CPU's instruction registers bit by bit. Next time improve your code.

  • @bit-machine

    @bit-machine

    8 ай бұрын

    Understood. I'm a failure, you're right.

  • @Misteribel

    @Misteribel

    8 ай бұрын

    😂😂😂😂

  • @atimholt

    @atimholt

    8 ай бұрын

    Arch Linux? Don't you mean Gentoo?

  • @tamnker8465

    @tamnker8465

    8 ай бұрын

    Arch Linux? Hark! Real coders don’t need an operating system. They connect wires directly to the computer and know what’s happening by listening to the hard drive.

  • @simiuciacia

    @simiuciacia

    8 ай бұрын

    I too use Arch btw

  • @KnightMirkoYo
    @KnightMirkoYo8 ай бұрын

    Anyone who looked at that code and said "look, O(n^2)!" has to get back to learning instead of critisizing/offering advice-

  • @maxtwist3598

    @maxtwist3598

    8 ай бұрын

    yes O(cn), I don't understand why n squared. That not the same length.

  • @a_soulspark

    @a_soulspark

    8 ай бұрын

    ​@@maxtwist3598 umm actually, in the video he said it's O(nm), not O(cn)!! get your facts checked 🤓

  • @fireninja8250

    @fireninja8250

    8 ай бұрын

    To be fair, having a system where there are more than 2 nested loops means your code will probably mean exponential more time

  • @ablobofgarbage

    @ablobofgarbage

    8 ай бұрын

    @@fireninja8250 that is just not true, if you have a finite amount of loops it will be polynomial time at worst.

  • @ME0WMERE

    @ME0WMERE

    8 ай бұрын

    @@a_soulspark I'll assume you're being sarcastic, as the names of the constants are irrelevant

  • @Azleriooo
    @Azleriooo8 ай бұрын

    Only real issue was indeed not having the limit be separate, which was really a simple fix, everything else was either nitpicking or simply plain wrong. Good follow-up video!

  • @bit-machine

    @bit-machine

    8 ай бұрын

    Thank you! Glad you like it

  • @rafaelclp

    @rafaelclp

    8 ай бұрын

    Agreed. I haven't watched the previous video, but when I saw the old solution in this one that's the only relevant problem that came to mind as well. Of course, in a real software no one should be abstracting that function BEFORE there's a real use case for dynamic rules; but that's beside the point.

  • @ChaosNe0

    @ChaosNe0

    8 ай бұрын

    sag's wie's is

  • @Wezla

    @Wezla

    8 ай бұрын

    100% this. It's absurd people mentioned the O(n2) thing. Reeks of first year students who know what things are, but don't think too deeply about what they mean.

  • @arjix8738

    @arjix8738

    8 ай бұрын

    but the loop started iterating from the 2nd index (1), the first index (0) was never reached you are only complaining about aesthetics at this point

  • @keen96
    @keen968 ай бұрын

    I swear reading the comments on the other video was infuriating lmao specially the big O ones. they read like college kids who just learned about it this semester and think they understand the concept perfecly

  • @yourmomsboyfriend3337

    @yourmomsboyfriend3337

    8 ай бұрын

    The problem wasn’t the runtime, it was the unreadability. Tom’s solution was extremely simple and easy to read, required no documentation, and functioned properly. The solution provided here was extremely difficult to read, even if convenient with an input required knowledge of the code that wasn’t provided, and overall over complicated simple and effective code.

  • @batatanna

    @batatanna

    8 ай бұрын

    The unreadability of a code is directly proportional to the reader's lack of coding skill. The code is very clear at what it does to each rule and anyone could deduce what's happening if they understand basic javascript. You, as the coder, do not need to know the full context of the program if your duty is to just change the logic and the same is true if you're to change the rules, in fact, in real projects you'll rarely know the full context of the application. @@yourmomsboyfriend3337

  • @cheerio662

    @cheerio662

    8 ай бұрын

    @@yourmomsboyfriend3337 This is not difficult to read at all. Not even a little bit. If someone struggles to read this its because they aren't competent enough to, not because its unreadable.

  • @yourmomsboyfriend3337

    @yourmomsboyfriend3337

    8 ай бұрын

    @@cheerio662 wonderful. Thanks so much for your input, would love to hear you explain how this solution is more readable than Tom’s. Go on, I am waiting. And if I want to add a change where if a number is a factor of 2, print out “Wazz” and do not do anything else, tell me, which version of code would you prefer to adapt and change, Tom’s or this one? Because this one needs to be completely refactored

  • @stevenismart

    @stevenismart

    8 ай бұрын

    ​@@cheerio662lack of readability doesn't imply lack of understanding. The array could be stored in a separate file and you would have to look it up to see that the objects don't have the same properties based on indexes. It also isn't typescript friendly so it probably won't work well with the intellisence of your IDE.

  • @TakeruDavis
    @TakeruDavis8 ай бұрын

    The heterogeneousness of the array was the only thing I had an issue with. Those who called YAGNI completely missed the point of Tom's video and those who thought complexity grew way out of proportion probably didn't even understood the original code to begin with. I actually thought of this kind of solution back when I watched Tom's video. And after working with code that was not future proofed at all, I'm trying to code parametrically, always thinking back to that video.

  • @Anohaxer

    @Anohaxer

    8 ай бұрын

    It's not even necessarily heterogeneous - while it may seem that it contains separate structures, that can actually be entirely fine. Conceptually, those were all rules, so their type would be something like Rule, not simply "an object with this exact structure". Declaring that there exist both a LimitRule and a ConditionalOutputRule, the whole thing is suddenly not heterogeneous but polymorphic. If you're expecting an interviewer to start asking you to implement all sorts of rules it may even be a preferrable option. In this case keeping the limit separate is just a better, simpler choice though.

  • @whossname4399

    @whossname4399

    8 ай бұрын

    Future proofing often leads to code that is far too difficult to read. If the requirements change, you are likely going to need to rewrite the relevant code anyway.

  • @VojtaJavora

    @VojtaJavora

    8 ай бұрын

    ​​@@Anohaxerthe problem is once you do ruleset[n].number and get undefined. That's why it's heterogeneous.

  • @Anohaxer

    @Anohaxer

    8 ай бұрын

    @@VojtaJavora Only as it is written. Conceptually it need not be. In js in the way it is written here, yes, it's going to give you undefined. That doesn't mean that it isn't a homogenous array of rules.

  • @user-dj1xq4yd6g
    @user-dj1xq4yd6g8 ай бұрын

    The O(n^2) guys shows a real problem that exists not only in programming but also in math and other natural science fields, and perhaps beyond that: Replacing understanding with rules. The "rule" is that two nested loops lead to O(n^2) so knowing that they don't "need" to understand what time complexity really is, how a computer works or how an algorithm is really logically structured. The problem isn't that they were wrong, the problem is that they either didn't think about the code for more than 5 seconds because of the rule, or couldn't understand how the computer would actually execute the code even if they thought about it because of over reliance on a rule. As a similar example there are some great videos out there criticizing PEMDAS for this same reason, like this one: kzread.info/dash/bejne/noB3psWaZse_oKQ.html. A completely non-issue for those of us who actually understand math, but a big issue for those who are taught rules instead of meaning.

  • @MrEmub
    @MrEmub8 ай бұрын

    Too be fair this final version is slightly easier to understand as a glance, and I'm not afraid to admit, I did learn something about "big o", thanks.

  • @avidrucker
    @avidrucker8 ай бұрын

    This is a well made and well thought out follow up video. Thank you for making it!

  • @bit-machine

    @bit-machine

    8 ай бұрын

    Glad you enjoyed it!

  • @manuel.a.vinces2017
    @manuel.a.vinces20178 ай бұрын

    Really. With the short time I've been involved in the coding world, one of the things I've learned very well is one of the golden rules: at the table you don't talk about: politics, religion, or programming paradigms. People can be very ridiculously fundamentalist and touchy on any of those topics. I'm telling you, as a very rookie rookie: your code was perfectly understandable and 100% readable even for a bug like me. Ps: yes, the heterogeneous array was noisy to me too.

  • @maksymiliank5135

    @maksymiliank5135

    8 ай бұрын

    Yes. It always comes down to OOP vs Functional (which most of the time is just procedural/imperative), dynamic vs static vs duck typing (if it is a duck and quacks like duck then it is a duck), haskell users talking about their monadic endofunctors and so on and so forth. People get very emotional when someone talks badly about their favorite programming language or paradigm

  • @manuel.a.vinces2017

    @manuel.a.vinces2017

    8 ай бұрын

    @@maksymiliank5135 Thanks to you, now I have Duck Typing Land included in my map of Coding World. And I love it.

  • @Firegroupfugl
    @Firegroupfugl8 ай бұрын

    Honestly, I don’t actually think the code here is much better, but maybe it’s a preference thing. Like the regular if statements are perfectly readable and doesn’t overcomplicate things, which is good imo.

  • @hampustoft2221

    @hampustoft2221

    8 ай бұрын

    The task is to make the code "readable" for over thousands of if cases, having a if statment for each is readable in some ways as you can se excatly when the code enters the block. Having the array allows you to have a function that is small and still semi-redable. and the readbility of this function will be the same no matter the amount of rules in the ruleset array. whilst the simple approach loses readability for each if statment.

  • @mathboy8188
    @mathboy81888 ай бұрын

    My insta-reaction to that code is noticing that the logic for determining the string value for an integer n, call it FizzBuzz(n, ruleset), that (normally) returns one of { "Fizz", "Buzz", "FizzBuzz", n.toString() }, is embedded in the logic for looping through displaying the output. That's mingling together the core logic defining FizzBuzz (or some variant of it) with how it's being put to use (looping 1 to N) and how usage is being displayed (console). For a trivial example where you're striving for efficiency, that's more than fine, but if you were writing this professionally, you'd want to pass in the core FizzBuzz routine to a routine like ShowFizzBuzzResults, which loops through numbers and displays what FizzBuzz produced for them. To go even further (true overkill in a trivial case like this), you really need 3 routines here: the core logic FizzBuzz, your chosen usage of that routine (here evaluating FizzBuzz from 1 to N), and an output routine that takes the results of that usage and does something with them... probably either UI or storage (displays them to user, or saves them to a text file, or embeds them in html, or whatever). That's not exactly worthwhile here, and certainly isn't maximally efficient, but it is professional (maintainable, testable, flexible, intelligible, etc.).

  • @stevenismart
    @stevenismart8 ай бұрын

    All i have to say is that your video editing is good and you're making content which is doing more than most people. The first video probably wasn't the best but it's good to see that you made a correction. But it did get you 55k views so that's good. The algorithm promoted the video since everyone was commenting lol. The O n^2 guys, even though they were wrong, pulled in so much interactions

  • @bit-machine

    @bit-machine

    8 ай бұрын

    Thank you! Yes, I'm grateful for every comment.

  • @rrinto
    @rrinto8 ай бұрын

    My head started hurting when I heard someone said you turned the algorithm to O(N^2). Furthermore, sufficiently advanced compilers can unroll the inner for loop for you if you're using a compiled language and have declared the ruleset as something like a static/compile-time constant. The only other modification would be using string buffers, but that's for another language altogether, although, you always have to ask yourself: is this level of optimization worth it for a FizzBuzz program?

  • @DeuxisWasTaken

    @DeuxisWasTaken

    8 ай бұрын

    Sufficiently advanced compilers

  • @EldronGah

    @EldronGah

    7 ай бұрын

    IF it was O(n^2), the compiler unrolling it would make no difference at all, since it would still have n^2 checks to do, they are just putted flat instead of in a loop. For this video's example, for example, even if it was unrolled it would still be O(n*m).

  • @claytonharting9899
    @claytonharting98998 ай бұрын

    I think this is a great solution. I would prefer leaving the rules as a list of if’s myself, just because I KNOW management is gonna hit us with some strange logic that will not fit any rules setup you can imagine. “Hey I need every other multiple of 7 to print bingo, and if you’ve printed fizz and then bang, the next print should be TomScott” Adjusting the logic is easier when it’s all contained in the same place. That does miss the point of the video, but I figured having shoutouts for different kinds of maintainability was good. There’s always tradeoffs (except when code is objectively worse, like using no indentation)

  • @LevaniaMeyano

    @LevaniaMeyano

    8 ай бұрын

    I think it would be easy to add that logic. Since a dictionary/hashmap is being used for the ruleset. You can add additional keys to define the usage of those rules. And modify the function itself to run those rules if defined in the list. And then just track the last 2 outputs with either a queue like object.

  • @NuncNuncNuncNunc

    @NuncNuncNuncNunc

    8 ай бұрын

    @@LevaniaMeyano Putting rule logic in the loop defeats the purpose of the rule array which I think is the point @claytonharting9899 was making. No one looking at the rule array would have any idea what { number: 7, word: 'bingo' } would mean unless they looked at the loop, thus keep all the logic contained in the loop. Note: avoid using reserved words as keys.

  • @antdok9573
    @antdok95738 ай бұрын

    Good video editing skills and even better arguments and explanations for your approach.

  • @bit-machine

    @bit-machine

    8 ай бұрын

    Thank you

  • @Thezaccazzac
    @Thezaccazzac8 ай бұрын

    That " ( output || i )" is a nice touch

  • @minneelyyyy8923
    @minneelyyyy89238 ай бұрын

    this is a good video. it addresses the actual potential concerns like the weird choice to have a heterogeneous array for no reason and some other simple code fixes while also clearly explaining why some other concerns like big O are wrong.

  • @NuncNuncNuncNunc

    @NuncNuncNuncNunc

    8 ай бұрын

    What happens if the rules are in a different order?

  • @anog_jani
    @anog_jani8 ай бұрын

    Good distinction there on the complexity, I learned from that, thank you :)

  • @dtomvan
    @dtomvan8 ай бұрын

    Using rust proc macros, you could've done a zero overhead abstraction, in which any fizzbuzz ruleset compiles down to a single forloop with a sequence of ifs. This way you can get rid of looping through the rules at runtime.

  • @kangalio

    @kangalio

    8 ай бұрын

    Can't tell if this is satire or sincere

  • @aCrumbled

    @aCrumbled

    8 ай бұрын

    you're correct but still 🤓

  • @jcm2606

    @jcm2606

    8 ай бұрын

    I mean, at that point the compiler would probably be unrolling the inner loop by itself if it finds unrolling to be beneficial, which means that you get the ergonomics of a loop and the performance of straight sequential branches without needing to involve any proc macros or other forms of preprocessing.

  • @CamoEnjoyer
    @CamoEnjoyer8 ай бұрын

    My personal complaint would be that this is prepared for future changes if and only if those changes are adding another word for multiples of another number. If you wanted to check for another condition (whether it's prime, whether it's a square, etc) or have it do something else (remove words, for example) you would end up in a very confusing spot, where you would have to make the call to either add new notation to the ruleset and conditionals in the function, abandon the current method altogether or hardcode new conditions into the gameLogic function despite still passing in a ruleset with divisibility conditions. Of course you can't prepare for future use like that ahead of time, which is the main reason you shouldn't try to future-proof in this manner, but you could have made it imo easier to avoid if you had made just the inner for loop into a function by itself, which you can call on a specific number, this would make it more modular.

  • @user-dj1xq4yd6g

    @user-dj1xq4yd6g

    8 ай бұрын

    Also unnecessary. It can easily be made modular when it needs to be made modular since we are just talking about breaking out code. Without further context you can't tell whether or not it makes sense to future proof this function, but you can definitively say that this is a more likely expansion of the initial requirements as you are actually talking about functioality that exists and that can be generalized, parameterized and abstracted.

  • @hampustoft2221

    @hampustoft2221

    8 ай бұрын

    you need to have a limit on your generalized solution otherwise you need to solve all problems with one method. In this case the generalization was made that we only will continue to check for if a number is divisable by another (no left over after division). by adding requierments that it also should do x, y and z. you need to ask why dose this function need to do this. or am i solving the problem worng? Somtimes we create functions that are complicated just becuse the choosen solution is inefficient or waste full when one could use multiple smaller and easier methods together.

  • @greenstarlover1

    @greenstarlover1

    8 ай бұрын

    That approach would require switching the number attribute with a condition attribute (which takes the forms of a function), that way the user has a way to inject its own custom conditions.

  • @NuncNuncNuncNunc
    @NuncNuncNuncNunc8 ай бұрын

    @3:27 What output do you want for numbers divisible by 15?

  • @joshhull
    @joshhull8 ай бұрын

    This was really fun to watch. A lot of people are justifying the heterogeneous array as being normal in Javascript, or criticising it for being hard to read. I think you realised the biggest problem with it at some point in your video, and I'm curious as to why you didn't say more. The heterogeneous array is leaky. Since your rulesets don't actually start until the second element, the algorithm part of the program is forced to start at index 1, even though it doesn't care whatsoever what the limit is. This leakiness lead to you temporarily introducing a bug. At 3:13, you've paused to show us the refactored code, but the indexing at 1 is still there, which now skips the first ruleset. You've fixed that by the end of the video of course. Now that I've said my piece, I'm gonna go watch all your other stuff 😂

  • @zanderwohl
    @zanderwohl8 ай бұрын

    You're right. Separating business logic out of code as much as possible is almost always the more maintainable solution. Especially when you have 1000 customers and they all want custom FizzBuzz configuration. And each office has a default config. And users can also make a custom config for just themselves. And C-levels can "delegate" to secretaries who can then act as if their user account were configured as their bosses' accounts.

  • @whossname4399

    @whossname4399

    8 ай бұрын

    It depends. I've seen people write code for the 1000 different FizzBuzzes that immediately becomes technical debt because it wasn't needed, then the client asks for something the code doesn't do, and it's much harder to implement because of this technical debt.

  • @whossname4399

    @whossname4399

    8 ай бұрын

    My approach is to keep it simple, then add config with default values when clients start asking for stuff. Often, you don't know what people will want to adjust/configure until they start asking for it. Another comment mentioned the possibility of a rule that outputs "bingo!" and ignores all other rules if the input is 7. Another mentioned a rule that compares to the square instead of whether it is divisible.

  • @SiberHavoc
    @SiberHavoc8 ай бұрын

    The code you wrote was somewhat of a late Heureka moment for me! I took inspiration from it to make functions to control multiple UI elements at once in a way that's neat. 🎉

  • @Nerketur
    @Nerketur8 ай бұрын

    This works well if we only want to add word segments to the string for each number in the order of the ruleset. But my follow-up to that would be: okay, thats great, now add the ability to have some numbers (say multiples of 7) that ignore the rule and always print "bingo". Or, alternatively, some multiples have the order reversed. Someone would have to know more than just that variable to understand the program. As written, they would need to know that order still matters, and that the strings concatenate.

  • @chri-k

    @chri-k

    8 ай бұрын

    that's unavoidable. You have to make some assumptions about the future if your code is to be readable.

  • @Nerketur

    @Nerketur

    8 ай бұрын

    @@chri-k You are correct. My point was simply that any "optimization" you do will eventually involve tradeoffs in something else. For example, the fastest way to print the numbers 1-10 isn't even using a loop. It's writing those numbers directly into the character buffer. But if you do that, and then later want 30 to 1000 instead, you'd then have to change the entire program. You will always make some assumptions about what the future will hold. I feel it is usually better to hold off on assumptions that _limit_ your options until you are relatively hard-set into going one way. Until then, keep the options as open as possible, rather than trying for as fast as possible.

  • @toast_on_toast1270
    @toast_on_toast12708 ай бұрын

    My only comment from the last one was to consider how to make it branchless (just as an excercise really), so I like the use of the OR operator. However, can the other if statement (checking the rule) also be made brachless?

  • @ChrisCox-wv7oo
    @ChrisCox-wv7oo8 ай бұрын

    "I know, the guy can't write code." Holy hell, that slayed me.

  • @sinom
    @sinom8 ай бұрын

    In a compiled language like rust/cpp/etc. that loop will most of the time not introduce any or at most minimal overhead. For a short enough array rhe compiler will just unroll the loop during compilation, and if it doesn't then there usually is a good reason for why the compiler doesn't. So I wouldn't look at that as an actual performance issue

  • @hallrules
    @hallrules8 ай бұрын

    I liked your original solution, and separating the rules and limit and making them const really helped clean up the code and made it better👍

  • @bit-machine

    @bit-machine

    8 ай бұрын

    Thank you

  • @SimGunther
    @SimGunther8 ай бұрын

    Congrats! You rediscovered the dictionary with the rules constant! Here are possible improvements to be had: const rules = { 3:"Fizz", 5:"Buzz" // more rules here... }; const limit = 100; for (let i = 1; i

  • @Schnorzel1337

    @Schnorzel1337

    8 ай бұрын

    Much better, always prefer the foreach loop.

  • @retardman6472

    @retardman6472

    8 ай бұрын

    Very nice, your code is very simple and readable.

  • @jcm2606

    @jcm2606

    8 ай бұрын

    Performance is probably worse due to the hashing of the dictionary key, assuming that JS is using a hash map for dictionaries (I have very little experience with JS so don't know). I can't really see a need for a dictionary in this case since you're always going to be iterating over the keys and you'll always be using the key in a calculation, so you might as well just iterate over the values too by pairing keys with values and iterating over each pair. Can do that as a tuple or an object, object would probably be better for readability when defining the ruleset. Bonus points if you're using a language that supports destructuring.

  • @NuncNuncNuncNunc

    @NuncNuncNuncNunc

    8 ай бұрын

    I want BuzzFizz instead of FizzBuzz. Does your solution still work?

  • @SimGunther

    @SimGunther

    8 ай бұрын

    @@NuncNuncNuncNunc LOL swapping the text in the dictionary will make it work to your specs, buddy

  • @michawhite7613
    @michawhite76138 ай бұрын

    What happens if my next question is to make so that if the number is divisible by 11, you print "Blue" and nothing else.

  • @DeuxisWasTaken
    @DeuxisWasTaken8 ай бұрын

    btw what language do you primarily use? Asking purely out of curiosity, because the heterogenous array suggests a functional language with lists and {Head | Tail} semantics like Erlang, while using 3-statement for loops in JS suggests an imperative/structured language like C/C++/Java.

  • @bit-machine

    @bit-machine

    8 ай бұрын

    Python and JS. I used JS for the video as that's what Tom used in his.

  • @Misteribel
    @Misteribel8 ай бұрын

    Any code will inevitably be optimizable, either for readability or arch, or for speed or target systems. On the latter, for instance, you can unroll the loop. Or you can inverse the logic (precalc). But the real kicker for speed would be to pre-allocate the target string (or use a string builder) and log all at once at the end. The logging is IO and, therefore, by far the slowest part. Which, incidentally, is why you didn't see big timing differences. You did well by timing before optimizing. I've seen people unrolling loops while writing data to databases. Pick your battles. Don't over optimize or optimize too early (but not too late either!).

  • @alinayossimouse
    @alinayossimouse8 ай бұрын

    Are you using text to speech for your voice over? I'm a bit confused by the pronunciation of integer and overhead, that's usually something TTS will do when missing context clues

  • @bit-machine

    @bit-machine

    8 ай бұрын

    Yep. I'm a machine after all :)

  • @greenstarlover1
    @greenstarlover18 ай бұрын

    As someone who abstracts the hell out of my functions, this is 100% would be my solution. The only change is that I would use a map function on the ruleset instead of a for loop (it would give a direct access to the object instead of using an index). Btw, the params of a functions in js are structured in the form of an heterogenous array also 😂

  • @greenstarlover1

    @greenstarlover1

    8 ай бұрын

    Also, if it was python, I would make the ruleset an ordered dictionary where the key is the number, and the value is the word. A dictionary is technically more efficient than an array.

  • @jollyjoker6340

    @jollyjoker6340

    4 ай бұрын

    I've been wondering if people just forgot ES6 exists

  • @martinybastiangomez9366
    @martinybastiangomez93668 ай бұрын

    Wait is fizz buzz a thing outside of my school?

  • @HansBezemer
    @HansBezemer8 ай бұрын

    If you happen to have so many values close together, you might want to use a table, where the index equals the search value. The other members simply contain a single "return" instruction. Sure, you have some function call overhead. It largely depends which language you're using. In C for example, most *switch()* statement are expanded to such a table automatically when optimizing. You can catch the "out of range" values by using *Min()* and *Max()* functions and reserving dummy entries for them. I used this trick intensively when creating my Basic interpreter - by using the token value as an index. It sped up the whole shebang quite nicely.

  • @H4KnSL4K
    @H4KnSL4K3 ай бұрын

    Thanks for the clear explanation! However, the code style (e.g. whitespace) still leaves improvements to be desired.

  • @JamesTM
    @JamesTM8 ай бұрын

    If there's one thing I've learned in my decade of professional development and years of tutoring, it's this: a surprising number of people get really, really confused about computational complexity, regular expressions, and pointers.

  • @ar_xiv
    @ar_xiv8 ай бұрын

    I mean a struct would be better than an array for the ruleset (is this javascript? can you do that?) but other than that it's very reasonable

  • @rednicstone3299
    @rednicstone32998 ай бұрын

    I don't really see why its required to go trough every rule in the ruleset with every iteration of i. It's impossible for an integer to be divisible by a number bigger than itself. Therefor I propose adding the following statement before line 11: 'if (ruleset[j].number > i) break;' (this is c-like syntax). This will, on average, double the speed. Of course an augment can be made that for small rulesets it could be more expensive for the CPU to mispredict the branch here (and clear the pipeline), but this can not be said for certain without a benchmark.

  • @bit-machine

    @bit-machine

    8 ай бұрын

    That's actually a pretty good point.

  • @Nerketur

    @Nerketur

    8 ай бұрын

    This is this is only true if the array is sorted by number. As written, this will not always be true. As written, order matters.

  • @rednicstone3299

    @rednicstone3299

    8 ай бұрын

    @@Nerketur Thats true, but this is enforcable / computable at compile time.

  • @Nerketur

    @Nerketur

    8 ай бұрын

    ​@@rednicstone3299yes, but not in Javascript, which Tom Scott used in the original. There is no compilation step. Sure, you could also sort the array before running it, but then you couldn't change the order of the word-segments by simply changing the order of the array values. (e.g. instead of FizzBuzz, printing BuzzFizz.) With the requirement of sorted arrays it's both more fragile and even more limiting in scope. It's true it would speed up the program (with the caveat of longer initial loading time), but that change would also have it deviate even more from Tom's solution, as his solution doesn't do any early backing out.

  • @ablobofgarbage
    @ablobofgarbage8 ай бұрын

    Is the voice AI? Pronunciation and intonation is a bit weird sometimes. Otherwise great improvement!

  • @bit-machine

    @bit-machine

    8 ай бұрын

    Yes, it is. Thank you

  • @do0nv

    @do0nv

    8 ай бұрын

    ​@bit-machine wait what

  • @bit-machine

    @bit-machine

    8 ай бұрын

    @@do0nv You can watch my early videos if you want to listen to my actual voice. Get some tissues ready though because your ears will bleed.

  • @ablobofgarbage

    @ablobofgarbage

    8 ай бұрын

    @@bit-machine I've checked out your first video and I'm not sure what you mean? Your voice sounds completely fine!

  • @ajinkyakamat7053
    @ajinkyakamat70538 ай бұрын

    Using C++'s fold expressions, you can keep the ruleset and write code that has zero performance overhead as compared to code with manually written if else statements.

  • @furyzenblade3558
    @furyzenblade35588 ай бұрын

    Which text to speech model did u use?

  • @bit-machine

    @bit-machine

    8 ай бұрын

    Play.ht

  • @furyzenblade3558

    @furyzenblade3558

    8 ай бұрын

    @@bit-machine thank you!

  • @ShuAbLe
    @ShuAbLe8 ай бұрын

    I've saw the other video and read the comments, I found then a bit harsh. Both nice videos.

  • @KDSBestGameDev
    @KDSBestGameDev8 ай бұрын

    const ruleset = { limit: 100, rules: [{number: 3, word: 'Fizz'}, ... ]; would be my prefered one, but that is personal preference. the loop overhead is something that you won't optimize in a length below 10.000/100.000. I do alot of performance optimization at my work and from experience noone cares about O(whatever). Just measure it with a profiler or like you did. I can show you O(n) code that is super slower. If you complain and say that just because there is a inner loop so it is O(n^2) then you don't have understood the O notation. Since the ruleset is const, I would even argue that the O(n) is correct and not O(nm). Depending on compiler and so on the inner for loop might even get optimized and becomes unrolled. I like both videos :)

  • @bit-machine

    @bit-machine

    8 ай бұрын

    Thanks for the feedback.

  • @TheArrowedKnee

    @TheArrowedKnee

    8 ай бұрын

    Another thing that people forget is that o(1) does actually matter quite a lot in reality. In other words, at smaller Ns, the constant time of an operation usually matters heck of a lot more than the size of an array or whatever.

  • @jetseverschuren
    @jetseverschuren8 ай бұрын

    I agree that the array wasn't too nice, but it being heterogeneous isn't my real issue. In JS it's fine to mix multiple types in an array, as long as they sort of represent the same thing, so you can easily iterate over the whole thing without special exceptions for, say, the first element. The would also allow you to change the C style for loop to (in my opinion) nicer for-of loop. And whilst I have a few more style/JS specific nitpicks, my real issue with this code (which also applies to the original), is that it's doing string operations for every single iteration. So more heap allocation, copying, etc. While for this size of set and computer speed it really doesn't matter, the embedded software engineer still wants something with slightly less unnecessary garbage creation

  • @Schnorzel1337

    @Schnorzel1337

    8 ай бұрын

    I think the first step is generating every possible fizz,buzz,bizz combination. IF we stay with only primes you can generate every combination beforehand so for example: 3: Fizz 5: Buzz 7: Bizz 3*5 = 15: FizzBuzz 3*7 = 21:FizzBizz 5*7 = 35:BuzzBizz 3*5*7 = 105 :FizzBuzzBizz That way you go from highest to lowest and as soon as you find one result you give the output. This way you generate about |k * k| rules which you can go through in logarithmic time or with space semi-/constant time. If you program in a language with pointers, maybe you can even get away with having every string only once so 105 is *pointerFizz + *pointerBuzz ... -- Intuition might be challenged, that you can just multiply the numbers and make up new rules like N % 105 => FizzBuzzBizz. That works because the lcm of primes is always their product. Would that be a better solution? You save on heapspace and gain proportionaly massive extra need for space.

  • @jetseverschuren

    @jetseverschuren

    8 ай бұрын

    ​@@Schnorzel1337 I think the easiest way is to just make a lookup table, where bit 0 of the index mean divisible by the first rule, etc. This would generate a lookup table of 2^m entries, but since you can directly calculate the offset into the table, complexity would still only be O(n*m) (where n is the limit, and m the amount of rules). And yes, it would cost quite a bit of heap, but if you have a relatively low amount of rules and a large limit it might be worth it

  • @maksymiliank5135

    @maksymiliank5135

    8 ай бұрын

    For of loop might be nicer to read but it is slower. (But honestly if you care about the performance then you shouldn't be using javascript in the first place)

  • @ultimatedude5686

    @ultimatedude5686

    8 ай бұрын

    @@Schnorzel1337That would take O(2^n) time where n is the number of rules. For smaller values of n that might be faster, but for larger values it’s much slower.

  • @arielaravena7249
    @arielaravena72498 ай бұрын

    1. You're right about the O notation, it's not O(n^2), it's what's generally refered to as O(nm), where m is a different factor 2. If performance is a concern, I feel like there could be room for improvement using the LCM, at least in the case of rules for 3 y 5: a. Calculate LCM = 15 b. Caculate how many times you can repeat the output = floor(100 / 15) = 6 c. Calculate how many iterations you'll have left after after repeating = 100 - 6 * 15 = 10 d. Iterate 10 times and save the current output e. Iterate the remaining 5 and save the current output f. Repeat the current output 6 times and add the output at 10 iterations It should be O(km) where k

  • @Schnorzel1337

    @Schnorzel1337

    8 ай бұрын

    Can you try to explain your algorithm more clearly? 1. I would say m is not what one would use, but k or d or similar. m implies its similar to n which it is not. 2. Nothing stopping you calculating lcm of many numbers so that also applies. As i understand: 2.b) You take the problem and divide it into chunks of size lcm(x1,x2,x3) 2.c) Every number outside of a chunk has to be treated different. 2.d) Iterate what over where? do you mean 1,2,Fizz,4,Buzz,....10? Okay we save 1 -> 10. 2.e) Iterate what over where? do you mean 11-> 15? Why not iterate the full 15 from the start? 2.f) What? [11-15],[11-15],[11-15],[11-15],[11-15],[11-15],[1-10]? That doesnt make sense. I think you are on a good path. The idea of reducing the problem into chunks of size lcm is great, because you always know the last element of your chunk. And if you calculated the chunk c1 you can immediately know the position of every fizz, buzz and fizzbuzz and so on for the chunk c2. If we allow c as the chunk number, starting on 0 and L as the lcm it is: [1+cL, 2+cL,Fizz,4+cL,Buzz,Fizz,7+cL,8+cL,Fizz,Buzz,11+cL,Fizz,13+cL,14+cL,FizzBuzz] [46 , 47 ,Fizz,49 ,Buzz,Fizz,52, 53, Fizz,Buzz, 56, Fizz, 58, 59, FizzBuzz] For c=3:

  • @arielaravena7249

    @arielaravena7249

    8 ай бұрын

    @@Schnorzel1337 Yeah, when I said iterate the remaining 5, I meant all in one loop, then the "current output" I suggested to duplicate is the output of the full "chunk"

  • @NuncNuncNuncNunc

    @NuncNuncNuncNunc

    8 ай бұрын

    You only need to precompute an array for the first 15 entries leaving null where the output is a number. For each i, i%15 is the index in the precomputed array. It is O(1).

  • @H4KnSL4K
    @H4KnSL4K3 ай бұрын

    I would also consider converting it to TypeScript and put types on things. For a toy problem like this it seems like unnecessary or ugly, but it does help to catch mistakes really quickly!

  • @felixjohnson3874
    @felixjohnson38748 ай бұрын

    Aside from minor implementation details I'd change this did fix most of the problems. With that said, I sincerely hope anyone who thought this was less performant and was an On^2 is not a programmer. There ARE cases where big O is hard, yes, but the logic of this is literally identical to Tom's and it's obscenely simple at that. Anyone who thought this was On^2 either just saw two loops and assumed any time there are two loops it's always On^2 or genuinely don't even know what On is, which does not bode well for the performance of their code.

  • @aDifferentJT
    @aDifferentJT8 ай бұрын

    The limit being part of the array is problematic for two reasons, one is that it’s heterogeneous as you said, the other is that it’s not clear what the semantic meaning of multiple limits should be.

  • @aronegill
    @aronegill8 ай бұрын

    Great video and excellent response. However I have to disagree on the console.log(output || i) line. You've made your code harder to read and it's unclear what the logical OR operation is doing. How is logical OR on a string and integer defined? should it return a boolean? why doesn't it return a boolean? in what cases will it return the string? Is it reading i as false if it's zero and true if it's not zero like in C?

  • @aronegill

    @aronegill

    8 ай бұрын

    Another solution is to use a ternary: console.log(output ? output : i); it checks the output, which always evaluates to true if there's something in the string, otherwise it evaluates to false. if it's true the string is not empty so we return it, otherwise we just print the number i

  • @Schnorzel1337

    @Schnorzel1337

    8 ай бұрын

    That is part of common javascript syntax. Everything in javascript is atleast truthy or falsey. So console.log(output || i) returns output if and only if the output is truthy. strings are truthy if they are not null or undefined and not empty. numbers are truthy, if they are not 0 or -0. It basicly works like this: a || b || c evaluates from left to right, the first truthy statement gets returned. So "abc"||"def" would return abc not abcdef. Now if you instead use | you simply get your first element. So the lesson, javascript is weird but that part is still widely used.

  • @kuba4ful
    @kuba4ful8 ай бұрын

    After months of working in Java, seeing you even able to declare an array without declaring it's type and mixing primitive types within is mindblowing

  • @Schnorzel1337

    @Schnorzel1337

    8 ай бұрын

    You can do the same in Java, because everything (besides primitives) is an Object so: Object[] = new Object[] { new Integer(1), "Hello", new ArrayList() }; is legal Java code. But never do it.

  • @TruthAndLoyalty

    @TruthAndLoyalty

    8 ай бұрын

    People often claim the flexibility of javascript is a strength. Those people are wrong.

  • @kuba4ful

    @kuba4ful

    8 ай бұрын

    @@Schnorzel1337 I hate the whole primitive-Object conversion so I try to keep everything in primitives unless I REALLY need to use Object (ex. with streamtokenizer, even then I convert it to primitive right after parsing it)

  • @Cydar0
    @Cydar08 ай бұрын

    Good video

  • @bit-machine

    @bit-machine

    8 ай бұрын

    Thank you

  • @DeuxisWasTaken
    @DeuxisWasTaken8 ай бұрын

    Yeah the heterogenous array hurts my eyes too, but not primarily for the reasons you mentioned. If you want to have a single well defined ruleset value, the obvious approach is having it be an object if you're not gonna iterate over the whole thing, so ``` const ruleset = { limit: 100, rules: [ {number: 3, word: 'Fizz'}, {number: 5, word: 'Buzz'}, ], } ``` This would result in both a less messed up ruleset structure and less messed up access of its rules. Arrays are for related data you'd like to iterate on, what you did was a masked object with unreadable access where instead of accessing named properties you have to remember which index stands for which property. Besides that issue (which you fixed), good points all around. Compilers unroll short loops anyway so the engine might've compiled basically the exact same thing,

  • @JorgetePanete
    @JorgetePanete8 ай бұрын

    Thank you, I watch this when I need to force vomit

  • @ChristianBrandoni
    @ChristianBrandoni8 ай бұрын

    The difference in your version and the previous version is a sort of micro optimization used in core loops in the old days with slow cpu. It's a sort of "loop unrolling" where you would remove a loop by simply writing the loop code inline sacrificing some flexibility in the code gaining some performance by avoiding some registers fetches. With modern cpu the gain is so negligible that it doesn't make much sense, plus modern compiler often does such optimization for you. Also "extreme" optimization and readability go into two opposite direction, cannot have both.

  • @izzeww8487
    @izzeww84878 ай бұрын

    that's an almost criminal pronunciation of "integers" :P EDIT: and that "for loop"? whaaaaaht, crazy :)

  • @bit-machine

    @bit-machine

    8 ай бұрын

    Yeah, the AI voice isn't always great😂. Still better than mine though

  • @cadekachelmeier7251
    @cadekachelmeier72518 ай бұрын

    I think pulling most of the inside into a "getFizzBizzString" method would be a good idea. Have it take a number and return a string. That would allow easier testing if that's a goal. It feels like the logic of generating the string is sort of independent of doing a specific loop or outputting it any particular place.

  • @kuba4ful
    @kuba4ful8 ай бұрын

    BTW, Important tip I could give you - Pin comment with this video link under the original one. 90% of people NEVER read descriptions, they may never notice there is a followup addressing criticism.

  • @David_Box
    @David_Box8 ай бұрын

    Most changes were good but the || suggestion is really bad for readability imo. It relies on truthiness (i think you should explicitly write what you are checking against), and it relies on the || operator's obscure conditional returning quirk. It's basiacally the same problem as the heterogenious list one, you should try to keep your types static (if you're planning long term, as the requirements imply). Therefore, only booleans should be used with logical operators. If you really still want to have a one-liner anyway, just use a ternary expression: console.log((output === '') ? i : output)

  • @DeusExAstra

    @DeusExAstra

    8 ай бұрын

    Agreed. It makes the mistake of thinking that just because some code takes up fewer lines, it's therefore easier to read. Often, it's the opposite.

  • @aDifferentJT

    @aDifferentJT

    8 ай бұрын

    I still don’t like having such core logic within the console.log call, when I see a console.log call I don’t expect it to be doing anything beyond formatting.

  • @mikefochtman7164

    @mikefochtman7164

    8 ай бұрын

    Indeed. Another way that would be very clear would be something like: if (output!=0) print output else print i Same comparison and you avoid one tiny assignment (setting output= i). But at this point it's more about clarity.

  • @AURORAFIELDS

    @AURORAFIELDS

    8 ай бұрын

    Honestly, as a JavaScript programmer, a ?? or a || is a lot more clean. in the latter case, you are doing something if the first case is unsuccessful. you're either printing the output or the iterator. it's really a tiny implementation detail that an empty string is the same as false. There's precedent for this, as this is also how C++ works, and indeed any check for a null terminator will be false, so arguably this precedent goes back to C. If you want to be pedantic about type-safety (and if you're programming in JavaScript, you're just not) then you should probably look at C# or Typescript instead. JavaScript and even most Typescript programmers will easily be aware of how truthy and falsy values work so || is going to be unambiguous and much quicker to parse

  • @RobBCactive

    @RobBCactive

    8 ай бұрын

    Nope, you're writing out a game word or the number, the || expresses that clearer than obfuscating control flow. If you find that strange or less readable than over-general control flow it's simply unfamiliarity. Eating out the menu says X or Y, you don't find it more readable to have if's and setting a choice.

  • @applebumpcaster8240
    @applebumpcaster82408 ай бұрын

    now i wonder, can others improve this?

  • @Schnorzel1337

    @Schnorzel1337

    8 ай бұрын

    You can in performance. Calculate the least common multiple of all rules, here 3*5 = 15. Create one chunk of size 15: 1,2,Fizz,4,Buzz,Fizz,7,8,Fizz,Buzz,11,Fizz,13,14,FizzBuzz. now every following chunk till infinity follows that pattern of number, number, Fizz, number, Buzz and so on. So the 1 Millions output will be the element at position 10 in our chunk (starting by 1) So 1 Million is Buzz. This is amazing, because it is easy to parallelize. You can spawn X threads each with the start number of their chunk and a representation of the makeup of a chunk. The problem really becomes, how do I save the numbers into a file or on the screen not fizzbuzz itself. The brightest implemenation creates fizzbuzz numbers at a rate of nearly 60 Gigabyte of fizzbuzz per second on a normal computer.

  • @atrus3823
    @atrus38238 ай бұрын

    One of the most annoying things in programming is when an idea becomes trendy and everyone regurgitates it without question for every situation . Premature optimization is not ever thinking about performance or the future or maintainability at all, it’s spending too much time on it with little prospect of return on investment. Like everything in engineering, there is a cost to adding things, but there can also be a cost to missing something. As you progress as a programmer, you’ll (hopefully) pick up on basic early optimization that costs basically nothing and can save a lot of headaches down the road.

  • @LightShoro
    @LightShoro8 ай бұрын

    Once again a rigorous proof that sometime the Internet takes things too seriously. No one here ever saw Tom Scott's video on bodges?

  • @AM-yk5yd
    @AM-yk5yd8 ай бұрын

    Akschually for (m I also would go with either Map(ES6 preserves insertion order) or array of tuples ([3, fizz]) or go full AOS vs SOA and go tuple/object of two JIT-happy arrays ([3,5,7], ["Fizz", "Buzz", "Fuzz"]). Most KISS is array of tuples. Using object for each entry is wasteful from memory perspecitve and names are bad (it's not "number", it's "factor" or something along the lines), but this is so nitpicky, Array of tuples is equally wasteful to array of objects, but I don't have to remember names, so it's KISSer. However it's nitpicky too much, I comment mostly to appease the algorithm not because cares was given.

  • @JoeDiPilato
    @JoeDiPilato8 ай бұрын

    def sln(mod_map,cnt): for c in range(1,cnt+1): res="" for num,string in mod_map: res+=(c%num==0)*string print(res or c) sln(mod_map=[(3,"fizz"),(5,"buzz"),(7,"jazz")],cnt=100)

  • @Templarfreak
    @Templarfreak8 ай бұрын

    while there is an argument to be made for separating out the limit into its own array, this is a problem specific to javascript (and other languages that share javascript's design principles). in a different language, keeping the limit in the same object as the ruleset is completely reasonable, such as in Lua. in Lua, you can define a key of a table to be the limit, and indexes of the array of the table to be the rules. in doing so, you will *never* iterate over the contents of the table's keys, such as the limit value, when doing a simple for loop, you will *never* accidentally read or modify the limit by accessing the indexes of the array, and you will *never* accidentally read or modify the indexes of the array by accessing the limit. so, while it is possible that those problems can happen in javascript, this is _not_ possible to happen in Lua barring extraneous circumstances. this just doesnt happen in Lua due to the way tables are structured and used. in javascript, you dont _exactly_ have these kinds of tools available to you, or at least not in a reasonable way, so it's understandable to want to make that change here, but for another language separating out the limit can *absolutely* make no sense to do. so i think your initial instinct in making it one object is nowhere near as wrong as other people were making it out to be. :D

  • @a4d9
    @a4d98 ай бұрын

    I would made at least one change to your final code, since you are repeating ruleset[j] for every access in the inner loop: for (const rule of ruleset) { if (i % rule.number === 0) output += rule.word; } Using for...of makes the code easier to read and It makes it clear that it is the same instance of the object from the array that is used at all locations. If you still want to use a traditional for-loop (sligtly faster), please extract the object at one place, and use that for all other accesses: for (let j = 0; j const rule = ruleset[j]; if (i % rule.number === 0) output += rule.word; }

  • @xcoder1122
    @xcoder11228 ай бұрын

    "Premature optimization" is only about performance, never about optimizing code for readability or maintainability. Premature optimization means people tend to make code faster, without even knowing if the code is slow to begin with and without knowing what aspects about the code is slow. So quite often they optimize code that would not even have required any optimization at all or they optimize something that is by far not the slowest part of the code, which will have little to no effect on the overall performance. You may argue: What's bad about that? This optimization didn't do any harm, right? But aside from the fact, that it was a waste of precious time, it quite often leads to code that is hard to read and hard to maintain, which would be somewhat acceptable if the optimization was really required but that's something you can only find out after writing readable and maintainable code and then profiling it. And on top of that, optimized code is more prone to bugs and because the code is less readable, those bugs are harder to spot and that's why premature optimization is bad. But optimizing for readability and maintainability is never premature as when would be the right time to do it? After writing the code? So you first want to write a version that is not readable and cannot really be updated in the future and once this is done, you revise it to make it readable and maintainable? That makes no sense unless you just want to sketch a proof of concept. And if you want to sketch a proof of concept, go for it but you should not use that as a base for the real solution. As "sketch" implies, this is just a quick and dirty implementation that only serves one purpose and is discarded once it has served its purpose. Once you know it is possible and how it can be done, you go back to the planing board and design a good implementation of it and you will not use your dirty sketch at all for that.

  • @HansPolak
    @HansPolak8 ай бұрын

    Oh… while you're at it, you could replace the offending array with an array of objects for added overhead. You can initialize the FizzBuzz object with an integer and a string, and have a function to return the string.

  • @atackhelikopter4303
    @atackhelikopter43038 ай бұрын

    idk man this shows more that humans will argue about everything, even if they are significant or elementary level as a person who learns cs and has done a LOT of complex problems, i find the code rather elementary and i was surprised to see people discus about "better" solutions when you have to do n steps and each step you have to answer k questions, thus getting O(n*k), regardless of the way you implement it, some solutions are more to the point while others are more generalized, but i would've written something similar, but a bit different, and i would use an array of pairs {int, bool}, one stores the modulos and the other one stores either a 0 or a 1, which can be used alongside a small array of strings of length 2, so you can instantly access the answer, also would personally shorten the code by doing tournery operators (or however they are called), in C++ the syntax is statement ? operation1 : operation2 but a LOT of programming is just preference or "coding style"

  • @DiegoLuiz
    @DiegoLuiz8 ай бұрын

    Now I'm happy haha thanks for separating the array.. I hadn't realized people said O(n^2) ahha that's funny because obviously it's not 🤣

  • @mujtabarehman5255
    @mujtabarehman52558 ай бұрын

    I'm not sure how people could even look at the code and think it ran in O(n^2) time. That shows a fundamental misunderstanding of analyzing time complexity. If you could not figure out that this code was O(nm), then I doubt you could meaningfully figure out the time complexity from any bit of code.

  • @Uebagi
    @Uebagi8 ай бұрын

    End up time complexity of O(100) and O(10^2) are the same.

  • @maciej.opalinski
    @maciej.opalinski8 ай бұрын

    Your solution is perfect for maintainability, I don't understand the hate...

  • @kangalio
    @kangalio8 ай бұрын

    Oh no don't double down on the overengineering Behavior should be expressed as code, not as a makeshift DSL (ruleset array) executed by a makeshift interpreter The goal is not to have an infinitely flexible function that can do everything you could possibly want in the future, given the correct inputs, because that is an uphill battle. The goal is to have a function that does exactly what it is meant to do in as straightforward and clear a way as possible, so changing requirements can _just change the code_

  • @MichaelAbramo
    @MichaelAbramo8 ай бұрын

    Why not a map instead of an array for the ruleset? You load the ruleset once and M is no longer a factor in the complexity. You have constant time retrieval for the num to the output. Then the complexity becomes O(n + m) instead of O(n*m) Surely the real execution time is negligible for this small sample size but I would use a map.

  • @jcm2606

    @jcm2606

    8 ай бұрын

    I can't see why a map would be beneficial for this snippet. The point of moving the rules into a dedicated ruleset list is to provide a central list of rules that you can iterate over, meaning that you would always be iterating over every single key in the map to check if the current number is divisible by the key. Since you're always iterating over every single key in the map it makes no sense to use a map since maps are typically designed for fast retrieval of values associated with _singular, known_ keys. You're not retrieving a value associated with a singular, known key, you're retrieving _all_ key-value pairs for the purpose of filtering down the keys to only those that pass the divisible check then adding the value of each key to a string that you're actively building, so it makes much more sense to just use a simple array of key-value pairs contained within tuples or objects/structs.

  • @NuncNuncNuncNunc

    @NuncNuncNuncNunc

    8 ай бұрын

    What kind of map? A plain javascript object or a Map object? If the lookup time for the map is constant, what is the overall complexity?

  • @NuncNuncNuncNunc
    @NuncNuncNuncNunc8 ай бұрын

    1) nitpick: using reserved word as field in rule object makes it harder to read - would not pass code review. 2) the ruleset is order dependent, but nowhere is this indicated or checked. While it may look like a clever solution because you can just add more rules to the list, this is not the case Separating the rules from the loop is not so much a matter of efficiency or readability but a design choice with its own tradeoffs. Which style implementation is a matter of how it will be used. Separating the rules from the loop may be flexible, but it offers up the chance for different loop implementations that apply the rules differently or conversely seemingly identical rulesets to be created which behave differently. Hint: the rules are not a Set

  • @rubinelli7404
    @rubinelli74048 ай бұрын

    My criticism is more philosophical than technical. Both you and Tom make assumptions that are nowhere in the original requirements. It's possible that the upper limit will change from 100, right. But what if the lower limit changes from 1? What if you receive a new business rule that doesn't follow the pattern "if n is divisible by X, append Y to the output" but instead creates a completely different exception? I understand the other side, as simple, "temporary" code can end up becoming crucial in production and be a huge headache to maintain, but I prefer to err on the side of YAGNI. You ain't gonna need it, and if you do, you can rewrite it with the knowledge that you gained -- and the time that you saved by writing the simplest code that could possibly work.

  • @TheArrowedKnee

    @TheArrowedKnee

    8 ай бұрын

    But then again, we're not talking about Fizz Buzz anymore, but something else entirely. This solution is just inherently following the rules of FizzBuzz, and there's nothing wrong with that.

  • @spaghettiking653

    @spaghettiking653

    8 ай бұрын

    Sure, I think this is completely valid, but that simply isn't what the FizzBuzz program is. What generalized version you write depends on what you envision you're gonna want to extend it to do. Given that FizzBuzz by itself doesn't really entail any particular extension (it's a really simple premise), the specific generalized solution you may wish to write is entirely in the eye of the beholder, so to speak. If you want to generalize it in the way Tom and this video do, so that the rules are all centered around string concatenation based on divisibility, there should be no better way of doing it; contrarily, if you anticipate some more drastic logic changes, then this specific method is likely not going to cut it, and needs modification. Insofar as the original requirements go, really all of this is superfluous. But, actually, the requirements are whatever you decide them to be :)

  • @hugofontes5708

    @hugofontes5708

    8 ай бұрын

    Do you see any sense in the whole FizzBuzz challenge thing then?

  • @rubinelli7404

    @rubinelli7404

    8 ай бұрын

    ​@@hugofontes5708 Sure! This can actually tell a fair bit about how you parse and tackle an assignment. Do you ask questions and try to uncover hidden requirements? That alone would be a big plus if I were interviewing you. Do you work out the overall algorithm, or start coding and reach the result by trial and error?

  • @hugofontes5708

    @hugofontes5708

    8 ай бұрын

    @@rubinelli7404 okay, alright, that sounds reasonable, so do you think Tom brought up inadequate questions to his own challenge? Do they make sense?

  • @ArnarF
    @ArnarF8 ай бұрын

    i like the way the tts says for loops xD

  • @spaghettiking653
    @spaghettiking6538 ай бұрын

    Thank God, the amount of moronic nonsense that was spouted in the comments last time was nauseating. Well done with this follow-up explanation.

  • @thisguy.-.
    @thisguy.-.8 ай бұрын

    your sade from the wraths of the inferno for now, just be careful it dont happen again lol my own point about abstractions needing a better, more complex example still stands from my previous comment on the other video, but it is pretty nitpicky. altough thinking about it, you HAVE coupled all of the code together, so perhaps some functionality will be harder to change? unsure, this is why i prefer in depth examples for abstraction.

  • @ZipplyZane
    @ZipplyZane8 ай бұрын

    This isn't really a flaw, but to me this code begs to have a variable lower limit as well. And if you really want ro remove all redundancy, you could use an array of arrays, instead of objects. For readabilty, you could just shoe a comment that specifies what each number means. So something like this: const ruleset = [ // [number, word] [3, 'fizz'], [5 'buzz'], //... ] But using an object with named properties is probably an acceptable amount of repetition.

  • @ZipplyZane

    @ZipplyZane

    8 ай бұрын

    Someone else pointed out a version that might be even better: const ruleset = { // number: word 3: 'fizz', 5: 'buzz', //... } While this is technically now an object, it could be iterated like a sparse array. We're in JavaScript, so arrays are just special objects anyway. Though I guess there might be a time increase with either iterating through the empty objects or not using an iterator at all, and going with *.forEach* or *for in* or *for of* .

  • @AdroSlice
    @AdroSlice8 ай бұрын

    Honestly my biggest problem is how you format multilined lists xD

  • @lightning_11
    @lightning_118 ай бұрын

    Realistically, just pass -O3 to your compiler and the loop delay is history.

  • @hotharvey2
    @hotharvey28 ай бұрын

    Most of these nitpicks seems to be more or less relevant depending on the imagined place this code lives. We have reached the point where there are only trade-offs rather than overall improvements

  • @8ytan
    @8ytan8 ай бұрын

    people need to understand that o(n) notation is a measure of how performance scales, not a measure of performance.

  • @4990UR05
    @4990UR058 ай бұрын

    Kudos for following up on the previous video! If I may add my two cents, here's a list of things I would change: 1. Limit and ruleset should be capitalised since they do not change during execution. This is a good practise so that other developers know that they can "trust" these values. Something like "const LIMIT = 100;" 2. I would separate concerns here. A function should run the loop and print the data, and another should create the output. For that I would also use the reduce method of the Array prototype. The code looks like this: function checkInput(input) { return RULESET.reduce((output, {number, word}) => `${output}${ input%number === 0 ? word : ''}` ,'') || input; } Of course, printing the output could also be delegated to another function. This addresses any readability concerns people have expressed, as a function can be trusted to work, and it is easier to debug. Moreover, this is a simple example, but in real life scenarios this logic helps a lot. 3. Just for the fun of it, I would also use recursion instead of a for loop. No actual additional value, but I mention it, just in case someone finds it useful. I hope these help :)

  • @pv2b
    @pv2b7 ай бұрын

    ruleset = [(3, "fizz"), (5, "buzz")] limit = 100 for n in range(1, limit+1): print(''.join(s for d, s in ruleset if n % d == 0) or n)

  • @balijosu
    @balijosu8 ай бұрын

    Wait, you mean KZread comments were wrong?? 😮

  • @williamdrum9899
    @williamdrum98997 ай бұрын

    Hot take: These kinds of questions are pointless, because at the end of the day your source code only loosely represents how the program is actually run. I'd be more interested in seeing how each of these compiles into bytecode or asm or whatever

  • @TheBuzzSaw
    @TheBuzzSaw8 ай бұрын

    In-tee-jurs? 😭

  • @bit-machine

    @bit-machine

    8 ай бұрын

    I know 😂 I probably should have regenerated the speech for that one. But I guess it's the charm of using AI voice?

  • @superderpyderps
    @superderpyderps8 ай бұрын

    Heterogeneity was mostly a theoretical problem, I wouldn't be surprised if it had negligible effects on speed. However, I think the real pain that was identified with that way of specifying limit was more about data access and single responsibility. Before you needed to access an array that was primarily giving actual fizzbuzz rules to parse a limit (which is a program rule, but not really part of each ruleset). Breaking it out of that array means the array is focused purely on a list of actual rulesets, and you can easily change your limit independently, which is more about maintainability and reducing unnecessary complexity. Not that it was _massively_ more complex, but it was unnecessary to collocate limit with the real rulesets. Then end result is just "cleaner code" for this example, though if you were to expand this to a more real world problem, these little details can add up enough to matter. Great work on the follow-up video. You took the criticism on the chin and explained both what could be improved and what was misunderstood by viewers. Ultimately, that's what separates a decent programmer from a great one.

  • @NuncNuncNuncNunc

    @NuncNuncNuncNunc

    8 ай бұрын

    It's not about speed with regard to the hlist. It requires more effort on the part of other coders to understand and it makes the ruleset less reusable. Bit-machine has still failed to recognize that the rules are order dependent. To solve just FizzBuzz, the rules must be sorted by the number field. In the original solution this would mean sorting the rules after dropping the limit element. At least with this solution it is only a matter of sorting before running the gameloop. An extra step is just a step to get wrong.

  • @anon_y_mousse
    @anon_y_mousse7 ай бұрын

    I borderline hate the FizzBuzz challenge. It's realistically impossible to improve without implementing a sieve, and with custom divisors you need to rethink the implementation for every change. The naive method sucks, but truthfully, it's not an operation that more than a handful of people would ever need, at least outside of these stupid challenges.

  • @DodoLP
    @DodoLP8 ай бұрын

    Those people who talked about "big O notation" or "nested loop" just heard those terms somewhere, they obviously dont even know what that is...

  • @bhavyajain638
    @bhavyajain6388 ай бұрын

    Can't we also make it more faster? Like if it's not divisible by 2, it's not divisible by any even number. So what if we group these conditions before using them in the loop?

  • @NuncNuncNuncNunc

    @NuncNuncNuncNunc

    8 ай бұрын

    Speed is not the first concern. One aspect of the fizz buzz test is that the programmer needs to recognize that the rules must be applied in a specicific order so grouping rules that are in some way similar in the rule list will likely not satisfy the requirements.

  • @AminalCreacher
    @AminalCreacher8 ай бұрын

    Huh... I left a comment here earlier and it's gone. It wasn't even mean... :'(

  • @NuncNuncNuncNunc

    @NuncNuncNuncNunc

    8 ай бұрын

    I've found on some videos that sometimes comments seemingly vanish and later come back. I wonder if it has to do with the way comments are distributed across the YT backend, e.g. there's a lag updating all machines so you may happen to hit a machine waiting for an update. Just a guess.

  • @AminalCreacher

    @AminalCreacher

    8 ай бұрын

    @@NuncNuncNuncNunc I think KZread will sometimes automatically block comments based on their content. A while back I attempted to provide some context to a clip of a, let’s say, “military incident,” but my comment was automatically deleted because I mentioned certain… military-related things that KZread didn’t like. Not gonna be specific for fear of this comment being auto-deleted. My comment on this video that was deleted contained a link to a codepen, and I think KZread doesn’t like links to external sites… not sure though. :(

  • @prawtism
    @prawtism8 ай бұрын

    Now I know how to pronounce heterogeneous, thanks :D

  • @framegrace1
    @framegrace18 ай бұрын

    "Permature optimization" doesn't exist. If you don't optimize the first time, it will not be optimized until it causes issues. Then usually is too late, and takes a lot more of time to fix it. Don't be lazy, don't be cheap. Optimize everything to the extend of your knowledge. Don't look for excuses. Is not that hard, it takes just some minutes more to stop and think.

  • @tylerbakeman
    @tylerbakeman8 ай бұрын

    The limit variable 👍. The rest of the code is technically slower than writing it explicitly - so the benefit would come from a large set of Fizzes. Warning: waste of time. If you want to get use out of your code (if you are targeting a large set of Fizzes), then you should try and optimize the arithmetic during looping. 1) what if you know ‘i’ is not divisible by the numbers of a subset of rulesets? then you can skip those iterations. 2) what if ‘i’ is prime, then you can skip all ruleset checks altogether. When it comes to prime number optimization, the math might will be difficult to derive- or impossible. Regardless. This is FizzBuzz - not even a significant problem to tackle.

  • @minamagdy4126

    @minamagdy4126

    8 ай бұрын

    Here's an idea: rather than check i % p == 0, you can add an array for each p denoting the next multiple. The inner-loop iteration could then be: if (i == nextExpected[p]) { nextExpected[p] += p toPrint += fizzMap[p] } I hope my naming scheme is clear. This could be significantly optimized, I'm sure, maybe even beyond what is demonstrated here. That said, it adds a new array of length m and indexing to it. One challenge would be refactoring the whole outer loop's body to optimize away some of the new flaws, or to better wield some of the new benefits. For example (now the whole program): // initialize nextExpected let nextExpected = {} for( p in fizzMap.keys()) { nextExpected[p] = p } for (i = 1; i