0

Looking for a way to put this logic into a list comprehension:

new_bills = []
for bill in bills:
    for gnr in bill["gnrs"]:
        if timestart <= gnr["date"] <= timeend:
            new_bills.append(bill)
            break
return new_bills

So, these are two nested dictionaries, and I only want the first instance of "bill" that fits the filter.

I used to have this:

return [bill for bill in bills for gnr in bill["gnrs"] if timestart <= gnr["date"] <= timeend]

However, this duped the bill object for everytime the if clause was met. Is there a way to get a list comprehension to behave like the for loop above? Keep in mind sets are out, as the bill is a dictionary (unhashable).

Edit for duplicate answer popup thing: The Solution turned out to be entirely different.

Berserker
  • 1,112
  • 10
  • 26
  • 6
    _"Looking for a way to put this logic into a list comprehension"_ Why? It's far more readable with normal loops. – Aran-Fey Mar 09 '18 at 10:57
  • 3
    Possible duplicate of [break list comprehension](https://stackoverflow.com/questions/9572833/break-list-comprehension) – Chris_Rands Mar 09 '18 at 10:58
  • 1
    look into `itertools.takewhile` – Jean-François Fabre Mar 09 '18 at 11:01
  • @Aran-Fey The comprehensions can (and usually are) built from a GUI, how readable the python code is, is often irrelevant. Expanding the GUI parser bit would mean some additional exceptions, which would then conflict with "Special cases aren't special enough to break the rules.". And would create more work than finding a solution compatible with the already established workflow. – Berserker Mar 09 '18 at 11:08
  • If it are complete duplicates you could perhaps try a set comprehension. If you insist on using a comprehension. – error Mar 09 '18 at 11:14

1 Answers1

1

Your inner loop is part of the filter:

new_bills = [
    bill for bill in bills
    if any(timestart <= gnr["date"] <= timeend for gnr in bill["gnrs"])
]
albar
  • 3,020
  • 1
  • 14
  • 27
emulbreh
  • 3,421
  • 23
  • 27
  • this doesn't really stops the list comprehension. It rather filters it. The only way to stop it is through aux functions passed to `for` like `itertools.takewhile` – Jean-François Fabre Mar 09 '18 at 12:03
  • [any](https://docs.python.org/3/library/functions.html#any) shortcircuits. – emulbreh Mar 09 '18 at 12:52
  • 1
    if won't shortcircuit `bills` in `for bill in bills`. I mean it's not going to stop iterating on it. It's just that `any` will no longer have a chance to return `True` after some iteration. – Jean-François Fabre Mar 09 '18 at 12:53
  • yes, that's exactly what the original for loops do. it's only breaking from the inner loop. – emulbreh Mar 09 '18 at 13:54