0

Let's say I have the dict below

{
    "1": {
        "rarity": 1
    },
    "2": {
        "rarity": 2
    }
}

and I want to find the amount of times rarity is 1. Instead of doing

count = 0
for x in dict.values():
    if x['rarity'] == 1:
         count += 1
return count

Is there a better way to do this? I found this post about using map, but I'm not sure how to get it to work with a nested dictionary.

Josh
  • 164
  • 4
  • 16
  • 1
    The way I'd write it is just `sum(1 for v in d.values() if v["rarity"] == 1)`. – Mateen Ulhaq Dec 05 '20 at 03:48
  • are you interested in knowing the working or just want to use it some where? – satvik Dec 05 '20 at 03:48
  • Efficient? In what sense? Also, your code doesn't seem to do what you say it should do. – Mateen Ulhaq Dec 05 '20 at 03:48
  • @jizhihaoSAMA with just that small sample set, `count` would be 1. @MateenUlhaq I guess I'm looking for the "proper" way. I feel like what I have works, but it's not proper because it's iterating each value in a for loop, when I think `map` or `lambda` may work instead. Also `x==4` should be `x['rarity']==1`, my mistake. – Josh Dec 05 '20 at 03:50
  • 2
    @MateenUlhaq it can be shorter `sum` also counts True values `sum(v["rarity"] == 1 for v in d.values())` – rioV8 Dec 05 '20 at 03:55
  • @rioV8 Nitpick: it's not something special `sum` is doing, that's just how bools work. `0 + True` -> `1` – wjandrea Dec 05 '20 at 04:30
  • more details: `isinstance(True, int)` evaluates to `True`. because `True` is an integer with the value of `1`. it's also its own class `bool`, which is a subclass of `int`. – acushner Dec 05 '20 at 04:42
  • len(v for v in d.values() if v["rarity"] == 1) – Daniel Farina Dec 05 '20 at 05:09
  • @Daniel `len()` doesn't work on iterators. – wjandrea Dec 05 '20 at 20:28

2 Answers2

0

You can use the following helper function with the map.

def functionHelper(value):
    if value["rarity"] == 1:
        return 1
    return 0
sum(map(functionHelper, d.values()))

or you can use one of these:

sum(map((1).__eq__, [v["rarity"] for v in d.values()]))
sum(v["rarity"] == 1 for v in d.values())
wjandrea
  • 28,235
  • 9
  • 60
  • 81
  • I think you accidentally combined the second two options so I edited to fix it. – wjandrea Dec 05 '20 at 20:34
  • The second `map` option has some problems. Use the generator expression instead. 1) Doing a `map` over a list comprehension means that the whole list is created first, *then* mapped. This is pointless and would be inefficient for large `d`. 2) Strongly avoid using dunder methods like `int.__eq__`. For comparison, [`int.__sub__(float)` instead of `int - float` doesn't work](https://stackoverflow.com/q/54775946/4518341). 3) It's longer and harder to read. – wjandrea Dec 05 '20 at 20:48
0

You can write it much shorter:

count = sum(v["rarity"] == 1 for v in d.values())

from rioV8's comment, with inspiration from Mateen Ulhaq's comment

wjandrea
  • 28,235
  • 9
  • 60
  • 81