def compile_id_list(self, polygon_id_list, nr_of_polygons):
        """
        sorts the polygons_id list from least to most occurrences of the zone ids (->speed up)
        only 4.8% of all shortcuts include polygons from more than one zone
        but only for about 0.4% sorting would be beneficial (zones have different frequencies)
        in most of those cases there are only two types of zones (= entries in counted_zones) and one of them
         has only one entry.
         the polygon lists of all single shortcut are already sorted (during compilation of the binary files)
        sorting should be used for closest_timezone_at(), because only in
         that use case the polygon lists are quite long (multiple shortcuts are being checked simultaneously).
        :param polygon_id_list:
        :param nr_of_polygons: length of polygon_id_list
        :return: sorted list of polygon_ids, sorted list of zone_ids, boolean: do all entries belong to the same zone
        """

        # TODO functional
        def all_equal(iterable):
            x = None
            for x in iterable:
                # first_val = x
                break
            for y in iterable:
                if x != y:
                    return False
            return True

        zone_id_list = empty([nr_of_polygons], dtype=DTYPE_FORMAT_H_NUMPY)
        counted_zones = {}
        for pointer_local, polygon_id in enumerate(polygon_id_list):
            zone_id = self.id_of(polygon_id)
            zone_id_list[pointer_local] = zone_id
            try:
                counted_zones[zone_id] += 1
            except KeyError:
                counted_zones[zone_id] = 1

        if len(counted_zones) == 1:
            # there is only one zone. no sorting needed.
            return polygon_id_list, zone_id_list, True

        if all_equal(list(counted_zones.values())):
            # all the zones have the same amount of polygons. no sorting needed.
            return polygon_id_list, zone_id_list, False

        counted_zones_sorted = sorted(list(counted_zones.items()), key=lambda zone: zone[1])
        sorted_polygon_id_list = empty([nr_of_polygons], dtype=DTYPE_FORMAT_H_NUMPY)
        sorted_zone_id_list = empty([nr_of_polygons], dtype=DTYPE_FORMAT_H_NUMPY)

        pointer_output = 0
        for zone_id, amount in counted_zones_sorted:
            # write all polygons from this zone in the new list
            pointer_local = 0
            detected_polygons = 0
            while detected_polygons < amount:
                if zone_id_list[pointer_local] == zone_id:
                    # the polygon at the pointer has the wanted zone_id
                    detected_polygons += 1
                    sorted_polygon_id_list[pointer_output] = polygon_id_list[pointer_local]
                    sorted_zone_id_list[pointer_output] = zone_id
                    pointer_output += 1

                pointer_local += 1

        return sorted_polygon_id_list, sorted_zone_id_list, False
sorts the polygons_id list from least to most occurrences of the zone ids (->speed up)
        only 4.8% of all shortcuts include polygons from more than one zone
        but only for about 0.4% sorting would be beneficial (zones have different frequencies)
        in most of those cases there are only two types of zones (= entries in counted_zones) and one of them
         has only one entry.
         the polygon lists of all single shortcut are already sorted (during compilation of the binary files)
        sorting should be used for closest_timezone_at(), because only in
         that use case the polygon lists are quite long (multiple shortcuts are being checked simultaneously).
        :param polygon_id_list:
        :param nr_of_polygons: length of polygon_id_list
        :return: sorted list of polygon_ids, sorted list of zone_ids, boolean: do all entries belong to the same zone