3
\$\begingroup\$

I have a positive integer n. I want to lazily loop over a range of integers less than n consisting of a) integers divisible by 3 (excluding zero) in reversed sorted order and b) zero and integers not divisible by 3 in any order. Is this a very stupid solution? I couldn't think of another way of doing it without having to make use two loops.

d = divisor = 3
list(itertools.chain(
    itertools.chain(*zip(*(((i),(i-1),(i-2)) for i in range(d*((n-1)//d),0,-d)))),
    (0,),range(n-1,d*((n-1)//d),-1)))

>>> n = 18
[15, 12, 9, 6, 3, 14, 11, 8, 5, 2, 13, 10, 7, 4, 1, 0, 17, 16]

>>> n = 17
[15, 12, 9, 6, 3, 14, 11, 8, 5, 2, 13, 10, 7, 4, 1, 0, 16]

>>> n = 16
[15, 12, 9, 6, 3, 14, 11, 8, 5, 2, 13, 10, 7, 4, 1, 0]

>>> n = 4
[3, 2, 1, 0]

>>> n = 3
[0, 2, 1]

>>> n = 2
[0, 1]

>>> n = 1
[0]
\$\endgroup\$
1
  • \$\begingroup\$ Why do you want zero in the second part? It is divisible by 3 (0 % 3 == 0) \$\endgroup\$
    – Caridorc
    May 23, 2015 at 11:41

2 Answers 2

2
\$\begingroup\$

Code is read far more often than written. So I prefer to make code as readable as possible. Clever code is very often not good code.

I find the posted code very hard to read, and I don't see why it has to be that way.

I believe this simple, straightforward implementation meets your posted requirements and very easy to read.

def gen(n):
    for x in range(n - 1, divisor - 1, -1):
        if x % divisor == 0:
            yield x
    yield 0
    for x in range(n):
        if x % divisor:
            yield x
\$\endgroup\$
5
  • 1
    \$\begingroup\$ I agree @janos. I made something very simple very complicated. I was too eager trying to avoid looping over the n range twice. I will leave my post as an example of how not to do things. \$\endgroup\$ May 23, 2015 at 15:25
  • \$\begingroup\$ Nice but you have some bugs: 0 may be anywere in the middle of the second part of the list, and the second part should be random \$\endgroup\$
    – Caridorc
    May 23, 2015 at 17:33
  • \$\begingroup\$ @Caridorc It works fine on my machine. \$\endgroup\$ May 23, 2015 at 17:38
  • \$\begingroup\$ @tommy.carstensen this programme misteriously works well only somewhere... anyhow thanks for testing it for yourself too. My output is pastebin.com/m5mcp8jx \$\endgroup\$
    – Caridorc
    May 23, 2015 at 17:52
  • \$\begingroup\$ @Caridorc The description says "any order", I assume that includes sorted too. I don't see a requirement for shuffled order, and the OP doesn't seem to miss it either ;-) \$\endgroup\$
    – janos
    May 23, 2015 at 19:04
1
\$\begingroup\$

You have a beatiful mind, my solution is as follows:

import random

def shuffled(lst):
    return sorted(lst, key=lambda *args: random.random())

def lazy_three_reverse(n):
    yield from range(n-3, 1, -3)
    yield from shuffled([i for i in range(0, n) if i % 3 != 0]+[0])

Testing:

>>> list(lazy_three_reverse(18))
[15, 12, 9, 6, 3, 5, 14, 10, 11, 7, 8, 4, 16, 17, 13, 2, 0, 1]
\$\endgroup\$
5
  • \$\begingroup\$ Python 3.x only. \$\endgroup\$
    – Caridorc
    May 23, 2015 at 11:47
  • \$\begingroup\$ Definitely more readable than my solution :) But you loop over the full range of integers twice. It makes almost no difference to the runtime of my code. It's just one of those optimisations I wanted to do for the fun of it :) I should probably prioritise readability instead. \$\endgroup\$ May 23, 2015 at 12:48
  • \$\begingroup\$ Your solution fails for n=17 and n=16. \$\endgroup\$ May 23, 2015 at 12:56
  • 1
    \$\begingroup\$ For people like myself that didn't know about yield from, then it's a new feature since version 3.3 described here: docs.python.org/3/whatsnew/3.3.html#pep-380 \$\endgroup\$ May 23, 2015 at 14:25
  • \$\begingroup\$ @tommy.carstensen on my computer it works... weird \$\endgroup\$
    – Caridorc
    May 23, 2015 at 17:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.