0

I've come across an interesting scenario while working on a Python program that involves generating unique options for a game. In my implementation, I initially used a set to store the options and encountered an issue where the program would freeze, leading to an infinite loop. However, after making a slight modification by switching to a list, the freezing problem disappeared.

I'm curious to understand the underlying reasons behind this behavior and why the second implementation caused the program to freeze. I have my own thoughts on the matter, but I want to gather insights from you all to gain a deeper understanding.

Prerequisite code

MAX = 20
MIN = 1

ans = random.randint(MIN, MAX)
y = random.randint(MIN, ans)
x = ans - y

Here are the two implementations:

Implementation 1 (No freezing issue):

opts = [x]
while len(opts) < 4:

    opt = random.randint(MIN, MAX)

    if opt not in opts:
        opts.append(opt)

Implementation 2 (Caused program freezing):

opts = {x}
while len(opts) < 4:
    opts.add(random.randint(MIN, MAX))

Edit

Here is the full contents of the function (with implementation 1)

def question_generator():

MAX = 20
MIN = 1

ans = random.randint(MIN, MAX)
y = random.randint(MIN, ans)
x = ans - y

# Generate options list
opts = [x]
while len(opts) < 4:
    opt = random.randint(MIN, MAX)
    if opt not in opts:
        opts.append(opt)

random.shuffle(opts)

return (x, y, ans, opts)

Questions I have about this:

  1. What exactly causes the freezing issue in the second implementation?

  2. Why does the first implementation resolve the freezing problem?

  3. Are there any underlying differences between sets and lists that contribute to this behavior?

I really can't seem to understand why there is such a drastic difference, thanks for any insight you may have.

rioV8
  • 24,506
  • 3
  • 32
  • 49
lt468
  • 81
  • 1
  • 7
  • 2
    Please update your question with sample values for `MIN` and `MAX`. – quamrana Jul 08 '23 at 08:52
  • also, a sample value for `x` would be useful. – slothrop Jul 08 '23 at 08:57
  • what is your `x` in `opts` though, because in terms of the code you provide, it works fine for me. It stops when `len(opts)=4`. – 8823 Jul 08 '23 at 08:58
  • Anyway, to see the key difference between sets and lists, do this. `my_set = {1, 2, 3}; my_list = [1, 2, 3]; my_set.add(3); my_list.append(3)`. Then print `my_set` and `my_list`. See the difference? – slothrop Jul 08 '23 at 08:59
  • Based on the example @slothrop, if the range you set between `MIN` and `MAX` are too close, i think that is the problem. – 8823 Jul 08 '23 at 09:04
  • @8823 my suspicion too. Like if `MIN = 2, MAX = 3`, the set will never reach 4 members. – slothrop Jul 08 '23 at 09:05
  • Done now @quamrana – lt468 Jul 08 '23 at 09:06
  • Your two snippets of code work out to be the same. The only possible reason for a freeze is that `randint()` occasionally may produce awkward values. – quamrana Jul 08 '23 at 09:11
  • I had been using MIN = 1 and MAX = 20. Sometimes it would freeze and other times it would not using the second implementation. It's just so the case that it hasn't happened at all using the first implementation. I get that you can't append duplicates to sets but I was thinking this would not be an issue because there would be more possible numbers and MIN and MAX were far enough apart. – lt468 Jul 08 '23 at 09:12
  • 1
    I am trying the second snippet and I can't get it to freeze... – quamrana Jul 08 '23 at 09:13
  • I ran for 15 minutes without a freeze. – quamrana Jul 08 '23 at 09:30
  • Possibly the rest of the function which is at fault? Which was, > random.shuffle(opts) > return (x, y, ans, opts) – lt468 Jul 08 '23 at 09:40
  • print the numbers you want to add to the set – rioV8 Jul 08 '23 at 09:45
  • I've added the rest of the function to the question. I know for sure that the issue was in this as the rest of my program worked. – lt468 Jul 08 '23 at 09:46
  • 1
    If `opts` is a set, then `random.shuffle(opts)` would fail - but it would throw an exception, not just freeze. – slothrop Jul 08 '23 at 09:49
  • 1
    Actually, can you show your full function with implementation 2? (because that would need to be somewhat different from implementation 1, e.g. no shuffle). Like @quamrana, I also haven't been able to make implementation 2 freeze. – slothrop Jul 08 '23 at 10:00

1 Answers1

0

In Python, when comparing the two data structures, “set” and “list”, one will immediately see significant differences and the best use cases for each.

Honestly looking at your use of both, I don’t think the program should freeze. But nevertheless, I’ll list some of the most common use cases so that you may profile your program and find the real problem.

  1. Lists are indexed while sets aren’t so sets do not support indexing or slicing operations.
  2. Although lists and sets are mutable, while elements of a lists are mutable, elements of sets are immutable. So an attempt to mutate an element of a set will not work.

Overall the add method of a set is efficient. And set is far faster, in general when testing for membership. In a list, this is O(n), linear in the size of the list. Adding to a set is O(1), independent of the number of the items in the set. stackoverflow answer

So the best way to tackle this would be profiling your program first to know if that is where the actual problem lies.

Drizzle
  • 198
  • 2
  • 11
  • *"So an attempt to mutate an element of a set will not work."* Specifically, mutating an element of a set in a way that changes that element's hash is indeed problematic: https://stackoverflow.com/questions/19953339/what-happens-when-objects-in-a-set-are-altered-to-match-each-other However, Python classes should be designed such that objects never change their hash during their lifetime (https://docs.python.org/3/glossary.html#term-hashable). So when that problem arises, it's arguably a "bad class design" issue rather than a "bad set usage" issue. – slothrop Jul 08 '23 at 09:38
  • @slothrop thanks for bringing this up and as a matter of fact I did keep this in mind when posting this but I am trying to find every possible reason why the program freezes to begin with. – Drizzle Jul 08 '23 at 09:45
  • More on what @slothrop pointed out. Consider mutation in code only when really necessary. These sources list many valid points on why mutation during a programs lifetime is a bad idea. https://en.m.wikipedia.org/wiki/Immutable_object, https://stackoverflow.com/a/30674260/16770846 – Drizzle Jul 08 '23 at 09:55