Repetition isn't necessarily a bad thing. If the repetition isn't difficult to alter and it more clearly describes what is happening on a step by step basis, it's difficult for me to call that "dirty".
Code is for humans, not computers, first and foremost. Certain things necessitate performance early on, but for a lot of projects it isn't reasonable for all code to make absolute logical sense from the get-go. What's more important is that people can read the code and understand it without undue deciphering.
Sometimes I come back to code that I've written long ago. When I wrote that code, I almost always thought I was writing "clean code". It often turns out that the code I was immediately able to understand and make changes to was the code that had repetition, wasn't mindlessly spread out into a bunch of "tiny functions", and had comments spread out to describe my reasoning.
In contrast, "clean" code is often inherently hard to change because it relies on centralizing functionality. When you centralize something and you change it, it may work for one circumstance but mysteriously cause something else to break. With repetition, your code base might be larger but code may be more decoupled and thus easier to make a small change to fix one thing without breaking another similar thing.