From 604861aa808d0ca1642332bbf72f3ec82a33b1c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9F=D0=B0=D0=B2=D0=B5=D0=BB?= Date: Wed, 8 Jan 2025 22:29:17 +0300 Subject: [PATCH] refactoring: represent binary ip as a string of length 32 --- cidr4_merger.py | 59 ++++++++++++++++++++++++++++--------------------- 1 file changed, 34 insertions(+), 25 deletions(-) diff --git a/cidr4_merger.py b/cidr4_merger.py index 0cc7dc7..92e0c63 100644 --- a/cidr4_merger.py +++ b/cidr4_merger.py @@ -1,6 +1,8 @@ from copy import deepcopy from ipaddress import IPv4Address from typing import List, Tuple +from itertools import groupby +from collections import defaultdict def get_data(input_file): @@ -15,43 +17,45 @@ def cidr4_to_binary(cidr4: str) -> str: ipv4 = IPv4Address(ip_str) binary_ip = bin(int(ipv4))[2:] binary_ip = binary_ip.zfill(32) - binary = binary_ip[:vlsm] + binary = binary_ip[:vlsm] + "0" * (32 - vlsm) return binary def binary_to_cidr4(binary: str) -> str: - vlsm = len(binary) - binary_ip = binary + "0" * (32 - vlsm) - int_ip = int(binary_ip, 2) + vlsm = binary.rfind("1") + 1 if "1" in binary else 0 + int_ip = int(binary, 2) ip = IPv4Address(int_ip) return f"{ip}/{vlsm}" def reduce_binary(binary: str) -> str: - if len(binary) == 0: - return "" - new_binary = binary[:-1] - if "1" not in new_binary: - return "" - return new_binary + assert len(binary) == 32 + vlsm = binary.rfind("1") + if vlsm == -1: + return binary + return binary[:vlsm] + "0" + binary[vlsm + 1 :] def rough_merge_binaries(binaries: List[str], req_len: int) -> List[str]: ips = set(deepcopy(binaries)) non_reducible_ips = set() reduction_limit_reached = False + max_vlsm = float("inf") while ( len(ips) > 0 and len(ips) + len(non_reducible_ips) > req_len and not reduction_limit_reached + and max_vlsm != -1 ): - max_vlsm = len(max(ips, key=lambda x: len(x))) + ip_with_max_vlsm = max(ips, key=lambda x: x.rfind("1")) + max_vlsm = ip_with_max_vlsm.rfind("1") + print(f"{max_vlsm=}") reduced_ips = set() merged_ips = set() for ip in ips: - if len(ip) == max_vlsm: + if ip.rfind("1") == max_vlsm: reduced_ip = reduce_binary(ip) - if len(reduced_ip) > 0: + if "1" in reduced_ip: reduced_ips.add(reduced_ip) else: non_reducible_ips.add(ip) @@ -62,6 +66,7 @@ def rough_merge_binaries(binaries: List[str], req_len: int) -> List[str]: ips = merged_ips else: reduction_limit_reached = True + print(f"{len(ips)=}") ips.update(non_reducible_ips) return sorted(ips) @@ -73,6 +78,7 @@ def main(): data = get_data(file) bin_ips = list(map(cidr4_to_binary, data)) + rough_merged_bin_ips = rough_merge_binaries(bin_ips, required_len) print(f"{len(rough_merged_bin_ips)=}") for ip in rough_merged_bin_ips: @@ -80,19 +86,22 @@ def main(): if __name__ == "__main__": - assert cidr4_to_binary("4.78.139.0/24") == "000001000100111010001011" - assert cidr4_to_binary("128.0.0.0/1") == "1" - assert cidr4_to_binary("0.0.0.0/0") == "" + assert cidr4_to_binary("4.78.139.0/24") == "00000100010011101000101100000000" + assert cidr4_to_binary("128.0.0.0/1") == "10000000000000000000000000000000" + assert cidr4_to_binary("0.0.0.0/0") == "0" * 32 + assert cidr4_to_binary("0.8.0.0/13") == "00000000000010000000000000000000" - assert binary_to_cidr4("000001000100111010001011") == "4.78.139.0/24" - assert binary_to_cidr4("1") == "128.0.0.0/1" - assert binary_to_cidr4("") == "0.0.0.0/0" + assert binary_to_cidr4("00000100010011101000101100000000") == "4.78.139.0/24" + assert binary_to_cidr4("10000000000000000000000000000000") == "128.0.0.0/1" + assert binary_to_cidr4("00000000000000000000000000000000") == "0.0.0.0/0" + assert binary_to_cidr4("00000000000010000000000000000000") == "0.8.0.0/13" - assert reduce_binary("000001000100111010001011") == "00000100010011101000101" - assert reduce_binary("1") == "" - assert reduce_binary("0") == "" - assert reduce_binary("") == "" - assert reduce_binary("0001") == "" - assert reduce_binary("0000") == "" + assert ( + reduce_binary("00000100010011101000101100000000") + == "00000100010011101000101000000000" + ) + assert reduce_binary("10000000000000000000000000000000") == "0" * 32 + assert reduce_binary("0" * 32) == "0" * 32 + assert reduce_binary("00000000000010000000000000000000") == "0" * 32 main()