Some of this is borrowed and scrubbed to protect the innocent. It's a stab at taking educated guesses at CIDR notations for sets of IP's. It's really only a guess but does a pretty good job at grouping.
use Socket; sub main { my @ips = qw( 192.168.1.1, 192.168.1.2, 10.15.15.1, 10.15.15.2, 172.129.4.1 ); test(@ips); } sub test { my @ips = @_; my $netmask = ip2int("255.255.255.0"); my %store; foreach my $ip (@ips) { my $int_ip = ip2int($ip); my $network_addr = network($int_ip, $netmask); $store{$network_addr}{$int_ip} = $ip; } while (my ($network_addr, $href) = each %store) { print int2ip($network_addr), "\n"; # sort IPs by value to display nice foreach my $int_ip (sort {$a <=> $b} keys %$href) { print " "x4, $href->{$int_ip},"\n"; } } } sub network { # logical AND of IP and netmask return $_[0] & $_[1] } sub ip2int { # this will only work for IPv4 return unpack('N', Socket::inet_aton($_[0])); } sub int2ip { return Socket::inet_ntoa(pack("N", $_[0])); } main();