Chalarangelo / 30-seconds-of-python

Short Python code snippets for all your development needs
https://www.30secondsofcode.org/python/p/1
Creative Commons Attribution 4.0 International
8.83k stars 1.26k forks source link

Ideas to improve `count_by` and others #409

Closed veronicaguo closed 3 years ago

veronicaguo commented 3 years ago

Hi, here are a few more minor improvement ideas as I continue going through the snippets. I'm happy to open a PR for them if they are useful.

  1. count_by: use defaultdict() to initialize the return dictionary, and increment in each loop.

    Current implementation:

    def count_by(arr, fn=lambda x: x):
      key = {}
      for el in map(fn, arr):
        key[el] = 1 if el not in key else key[el] + 1
      return key

    Can be refactored into:

    from collections import defaultdict
    
    def count_by(lst, fn=lambda x: x):
      count = defaultdict(int)
      for val in map(fn, lst):
        count[val] += 1
      return dict(count)
  2. chuck_into_n and initial

    • Refactor range(0, val) to range(val).
    • Refactor lst[0:-1] to lst[:-1].
Trinityyi commented 3 years ago

Thanks for the suggestions. Both seem valid. I'm assigning this to you, you can open a PR whenever you have the time.

JahnaviChitta commented 3 years ago

Hi, here is a different approach to count an element's occurrence in a list using list comprehensionand lambda functions.

lst = [1, 2, 3, 4, 9, 2, 2, 1, "apple", "ball", "apple"]
elementToBeSearched = 2
print(len(list(filter(lambda x : x == elementToBeSearched, l))))
vbrozik commented 3 years ago

@veronicaguo the collections module contains the class Counter intended exactly for this purpose. You can use count = collections.Counter() instead of count = collections.defaultdict(int)

or you can even initialize the counter directly from the iterable and the function will consist of a single expression:

import collections

def count_by(iter1, map1=lambda x: x):
  return dict(collections.Counter(map(map1, iter1)))

@JahnaviChitta There is no need to first create the list and then to count it (it could be really bad if it had millions of items). This code is counting the items directly: sum(1 for x in filter(lambda x : x == elementToBeSearched, lst))

...and Python generator expressions are much more powerful. The filtering can be part of the same expression: sum(1 for x in lst if x == elementToBeSearched)

...but anyway for the solution to be efficient in most cases it has to count the all the values in a single pass like do the original functions above.