code: def group_files_by_size_fast(fileslist, nbgroups, mode=1):
      '''Given a files list with sizes, output a list where the files are grouped in nbgroups per cluster.
      Pseudo-code for algorithm in O(n log(g)) (thank's to insertion sort or binary search trees)
      See for more infos: http://cs.stackexchange.com/questions/44406/fast-algorithm-for-clustering-groups-of-elements-given-their-size-time/44614
      For each file:
          - If to-fill list is empty or file.size > first-key(to-fill):
            * Create cluster c with file in first group g1
            * Add to-fill[file.size].append([c, g2], [c, g3], ..., [c, gn])
          - Else:
            * ksize = first-key(to-fill)
            * c, g = to-fill[ksize].popitem(0)
            * Add file to cluster c in group g
            * nsize = ksize - file.size
            * if nsize > 0:
              . to-fill[nsize].append([c, g])
              . sort to-fill if not an automatic ordering structure
          '''
      ftofill = SortedList()
      ftofill_pointer = {}
      fgrouped = []
      ford = sorted(fileslist.iteritems(), key=lambda x: x[1])
      last_cid = -1
      while ford:
          fname, fsize = ford.pop()
          if not ftofill or fsize > ftofill[-1]:
              last_cid += 1
              fgrouped.append([])
              fgrouped[last_cid].append([fname])
              if mode==0:
                  for g in xrange(nbgroups-1, 0, -1):
                      fgrouped[last_cid].append([])
                      if not fsize in ftofill_pointer:
                          ftofill_pointer[fsize] = []
                      ftofill_pointer[fsize].append((last_cid, g))
                      ftofill.add(fsize)
              else:
                  for g in xrange(1, nbgroups):
                      try:
                          fgname, fgsize = ford.pop()
                      except IndexError:
                          break
                      fgrouped[last_cid].append([fgname])
                      diff_size = fsize - fgsize
                      if diff_size > 0:
                          if not diff_size in ftofill_pointer:
                              ftofill_pointer[diff_size] = []
                          ftofill_pointer[diff_size].append((last_cid, g))
                          ftofill.add(diff_size)
          else:
              ksize = ftofill.pop()
              c, g = ftofill_pointer[ksize].pop()
              fgrouped[c][g].append(fname)
              nsize = ksize - fsize
              if nsize > 0:
                  if not nsize in ftofill_pointer:
                      ftofill_pointer[nsize] = []
                  ftofill_pointer[nsize].append((c, g))
                  ftofill.add(nsize)
      return fgrouped