【问题标题】:Simple way to group items into buckets将项目分组到存储桶中的简单方法
【发布时间】:2012-10-04 04:09:44
【问题描述】:

我经常想在 python 中存储一个无序的集合。 itertools.groubpy 做了正确的事情,但几乎总是需要先对项目进行排序,然后在迭代器被消耗之前捕获它们。

是否有任何快速的方法来获得这种行为,无论是通过标准 python 模块还是简单的 python 习惯用法?

>>> bucket('thequickbrownfoxjumpsoverthelazydog', lambda x: x in 'aeiou')
{False: ['t', 'h', 'q', 'c', 'k', 'b', 'r', 'w', 'n', 'f', 'x', 'j', 'm', 'p',
    's', 'v', 'r', 't', 'h', 'l', 'z', 'y', 'd', 'g'],
 True: ['e', 'u', 'i', 'o', 'o', 'u', 'o', 'e', 'e', 'a', 'o']}
>>> bucket(xrange(21), lambda x: x % 10)
{0: [0, 10, 20],
 1: [1, 11],
 2: [2, 12],
 3: [3, 13],
 4: [4, 14],
 5: [5, 15],
 6: [6, 16],
 7: [7, 17],
 8: [8, 18],
 9: [9, 19]}

【问题讨论】:

    标签: python


    【解决方案1】:

    这已经出现过好几次了——(1)(2)(3)——itertools recipes 中有一个分区配方,但据我所知,标准库中什么都没有。虽然我几周前accumulate 让我感到惊讶,所以谁知道这些天潜伏着什么? :^)

    当我需要这种行为时,我会使用

    from collections import defaultdict
    
    def partition(seq, key):
        d = defaultdict(list)
        for x in seq:
            d[key(x)].append(x)
        return d
    

    继续我的一天。

    【讨论】:

      【解决方案2】:

      这是一个简单的两个班轮

      d = {}
      for x in "thequickbrownfoxjumpsoverthelazydog": d.setdefault(x in 'aeiou', []).append(x)
      

      编辑:

      为了完整起见,只需添加您的其他案例。

      d={}
      for x in xrange(21): d.setdefault(x%10, []).append(x)
      

      【讨论】:

      • 我总是觉得defaultdict 比 d.setdefault.etc 类型的技巧更好
      • @wim:是的,我总是忘记它的存在。这就是为什么我对 DSM 的回答投了赞成票。
      • wim:实际上,我喜欢setdefault 胜过defaultdict。无论哪种方式,它的代码量几乎相同,但setdefault 对此很明确,您可以在发现需要时在现有字典上使用它。
      【解决方案3】:

      当谓词为布尔值时,这是上面partition() 的变体,避免了dict/defaultdict 的开销:

      def boolpartition(seq, pred):
          passing, failing = [], []
          for item in seq:
              (passing if pred(item) else failing).append(item)
          return passing, failing
      

      示例用法:

      >>> even, odd = boolpartition([1, 2, 3, 4, 5], lambda x: x % 2 == 0)
      >>> even
      [2, 4]
      >>> odd
      [1, 3, 5]
      

      【讨论】:

        【解决方案4】:

        如果它是pandas.DataFrame,则以下也适用,使用pd.cut()

        from sklearn import datasets
        import pandas as pd
        
        # import some data to play with
        iris = datasets.load_iris()
        df_data = pd.DataFrame(iris.data[:,0])  # we'll just take the first feature
        
        # bucketize
        n_bins = 5
        feature_name = iris.feature_names[0].replace(" ", "_")
        my_labels = [str(feature_name) + "_" + str(num) for num in range(0,n_bins)]
        pd.cut(df_data[0], bins=n_bins, labels=my_labels)
        

        屈服

        0      0_1
        1      0_0
        2      0_0
        [...]
        

        如果你不设置labels,输出会是这样的

        0       (5.02, 5.74]
        1      (4.296, 5.02]
        2      (4.296, 5.02]
        [...]
        

        【讨论】:

          【解决方案5】:

          编辑:

          使用 DSM 的答案作为开始,这里有一个更简洁、通用的答案:

          d = defaultdict(list)
          map(lambda x: d[x in 'aeiou'].append(x),'thequickbrownfoxjumpsoverthelazydog')
          

          d = defaultdict(list)
          map(lambda x: d[x %10].append(x),xrange(21))
          
          #

          这里有两个班轮:

          d = {False:[],True:[]}
          filter(lambda x: d[True].append(x) if x in 'aeiou' else d[False].append(x),"thequickbrownfoxjumpedoverthelazydogs")
          

          当然可以做成单线:

          d = {False:[],True:[]};filter(lambda x: d[True].append(x) if x in 'aeiou' else d[False].append(x),"thequickbrownfoxjumpedoverthelazydogs")
          

          【讨论】:

          • -1 键并不总是 False 和 True,它们应该是 callable 的输出
          • 我推荐for x in 'thequickbrownfoxjumpsoverthelazydog': d[x in 'aeiou'].append(x) 表格(如grieve 的回答)。我不太喜欢使用map 来处理副作用并丢弃价值。
          • 悲伤答案的问题,虽然效果很好,但它的计算成本更高。 (它为每个元素调用 setdefault,无论是否重复。)我喜欢 DSM 的回答,但我想看看我是否可以得到一个(或接近它)。
          • 如果您只是将两条线与; 连接在一起,这并不是真正的单线!
          • 我不是说不要使用defaultdict,我的意思是把for循环改成map并不会让它更简洁,只会让它更混乱。
          猜你喜欢
          • 2011-02-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-01-20
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多