              The range of data to separate into bins
          num_bins: int
              The number of bins to create
  
          Returns
          -------
          list
              The split dividers for the given number of bins for the given range
          """
          quotient, remainder = divmod(bin_range, num_bins)
          seps = [quotient + 1] * remainder + [quotient] * (num_bins - remainder)
          uplimit = 0
          bins = [0]
 
</s> remove         quotient, remainder = divmod(bin_range, num_bins)
        seps = [quotient + 1] * remainder + [quotient] * (num_bins - remainder)
        uplimit = 0
        bins = [0]
        for sep in seps:
            bins.append(uplimit + sep)
            uplimit += sep
        return bins

    @staticmethod
    def _convert_color(imgs, same_size, method):
        """ Helper function to convert color spaces """

        if method.endswith('gray'):
            conversion = np.array([[0.0722], [0.7152], [0.2126]])
        else:
            conversion = np.array([[0.25, 0.5, 0.25], [-0.5, 0.0, 0.5], [-0.25, 0.5, -0.25]])

        if same_size:
            path = 'greedy'
            operation = 'bijk, kl -> bijl' if method.endswith('gray') else 'bijl, kl -> bijk'
 </s> add         if self._args.group_method != "none":
            # Check if non-dissimilarity sort method and group method are not the same
            self._output_groups() </s> remove     def reload_images(self, group_method, img_list):
        """
        Reloads the image list by replacing the comparative values with those
        that the chosen grouping method expects.
        :param group_method: str name of the grouping method that will be used.
        :param img_list: image list that has been sorted by one of the sort
        methods.
        :return: img_list but with the comparative values that the chosen
        grouping method expects.
        """
        logger.info("Preparing to group...")
        if group_method == 'group_blur':
            filename_list, image_list = self._get_images()
            blurs = [self.estimate_blur(img) for img in image_list]
            temp_list = list(zip(filename_list, blurs))
        elif group_method == 'group_blur_fft':
            filename_list, image_list = self._get_images()
            fft_blurs = [self.estimate_blur_fft(img) for img in image_list]
            temp_list = list(zip(filename_list, fft_blurs))
        elif group_method == 'group_face_cnn':
            filename_list, image_list, landmarks = self._get_landmarks()
            temp_list = list(zip(filename_list, landmarks))
        elif group_method == 'group_face_yaw':
            filename_list, image_list, landmarks = self._get_landmarks()
            yaws = [self.calc_landmarks_face_yaw(mark) for mark in landmarks]
            temp_list = list(zip(filename_list, yaws))
        elif group_method == 'group_hist':
            filename_list, image_list = self._get_images()
            histograms = [cv2.calcHist([img], [0], None, [256], [0, 256]) for img in image_list]
            temp_list = list(zip(filename_list, histograms))
        elif group_method == 'group_black_pixels':
            filename_list, image_list = self._get_images()
            black_pixels = [np.ndarray.all(img == [0, 0, 0], axis=2).sum()/img.size*100*3
                            for img in image_list]
            temp_list = list(zip(filename_list, black_pixels))
        else:
            raise ValueError(f"{group_method} group_method not found.")

        return self.splice_lists(img_list, temp_list)

    @staticmethod
    def _near_split(bin_range, num_bins):
        """ Obtain the split for the given number of bins for the given range

        Parameters
        ----------
        bin_range: int
            The range of data to separate into bins
        num_bins: int
            The number of bins to create
 </s> add     def process(self) -> None:
        """ Main processing function of the sort tool </s> remove         logger.info("Sorting by percentage of black pixels...")
        img_list = [(filename, np.ndarray.all(image == [0, 0, 0], axis=2).sum()/image.size*100*3)
                    for filename, image, _ in tqdm(self._loader.load(),
                                                   desc="Calculating black pixels",
                                                   total=self._loader.count,
                                                   leave=False)]
        img_list_len = len(img_list)
        for i in tqdm(range(0, img_list_len - 1), desc="Comparing black pixels", file=sys.stdout):
            for j in range(0, img_list_len-i-1):
                if img_list[j][1] > img_list[j+1][1]:
                    temp = img_list[j]
                    img_list[j] = img_list[j+1]
                    img_list[j+1] = temp
        return img_list

    # Methods for grouping
    def group_blur(self, img_list):
        """ Group into bins by blur """
        # Starting the binning process
        num_bins = self._args.num_bins

        # The last bin will get all extra images if it's
        # not possible to distribute them evenly
        num_per_bin = len(img_list) // num_bins
        remainder = len(img_list) % num_bins

        logger.info("Grouping by blur...")
        bins = [[] for _ in range(num_bins)]
        idx = 0
        for i in range(num_bins):
            for _ in range(num_per_bin):
                bins[i].append(img_list[idx][0])
                idx += 1

        # If remainder is 0, nothing gets added to the last bin.
        for i in range(1, remainder + 1):
            bins[-1].append(img_list[-i][0])

        return bins

    def group_blur_fft(self, img_list):
        """ Group into bins by fft blur score"""
        # Starting the binning process
        num_bins = self._args.num_bins

        # The last bin will get all extra images if it's
        # not possible to distribute them evenly
        num_per_bin = len(img_list) // num_bins
        remainder = len(img_list) % num_bins

        logger.info("Grouping by fft blur score...")
        bins = [[] for _ in range(num_bins)]
        idx = 0
        for i in range(num_bins):
            for _ in range(num_per_bin):
                bins[i].append(img_list[idx][0])
                idx += 1

        # If remainder is 0, nothing gets added to the last bin.
        for i in range(1, remainder + 1):
            bins[-1].append(img_list[-i][0])

        return bins

    def group_face_cnn(self, img_list):
        """ Group into bins by CNN face similarity """
        logger.info("Grouping by face-cnn similarity...")

        # Groups are of the form: group_num -> reference faces
        reference_groups = {}

        # Bins array, where index is the group number and value is
        # an array containing the file paths to the images in that group.
        bins = []

        # Comparison threshold used to decide how similar
        # faces have to be to be grouped together.
        # It is multiplied by 1000 here to allow the cli option to use smaller
        # numbers.
        min_threshold = self._args.min_threshold * 1000

        img_list_len = len(img_list)
 </s> add         logger.debug("Cleaning arguments: %s", arguments)
        if arguments.sort_method == "none" and arguments.group_method == "none":
            logger.error("Both sort-by and group-by are 'None'. Nothing to do.")
            sys.exit(1) </s> remove         # If remainder is 0, nothing gets added to the last bin.
        for i in range(1, remainder + 1):
            bins[-1].append(img_list[-i][0])
 </s> add         logger.debug("Cleaned arguments: %s", arguments)
        return arguments </s> remove         return bins
 </s> add     def _get_sorter(self) -> "SortMethod":
        """ Obtain a sorter/grouper combo for the selected sort/group by options
        This method dynamically assigns the functions that will be used to run
        the core process of sorting, optionally grouping, renaming/moving into
        folders. After the functions are assigned they are executed.
              The range of data to separate into bins
          num_bins: int
              The number of bins to create
  
        This method dynamically assigns the functions that will be used to run
        the core process of sorting, optionally grouping, renaming/moving into
        folders. After the functions are assigned they are executed.
        This method dynamically assigns the functions that will be used to run
        the core process of sorting, optionally grouping, renaming/moving into
        folders. After the functions are assigned they are executed.
        This method dynamically assigns the functions that will be used to run
        the core process of sorting, optionally grouping, renaming/moving into
        folders. After the functions are assigned they are executed.
        This method dynamically assigns the functions that will be used to run
        the core process of sorting, optionally grouping, renaming/moving into
        folders. After the functions are assigned they are executed.
          """
          quotient, remainder = divmod(bin_range, num_bins)
          seps = [quotient + 1] * remainder + [quotient] * (num_bins - remainder)
          uplimit = 0
          bins = [0]
keep keep keep keep replace replace replace replace keep keep keep keep keep
 Overhaul sort:
  - Standardize image data reading and writing
  - Optimize loading (just one pass required)
  - Make all sort groups binnable (to greater or lesser results)
  - Add sort by pitch
  - Deprecate multiple options
  - linting, docs + locales 
tools/sort/sort.py