Has anyone implemented sorting a list of domain names?
I have seen some applications sort them as flat strings, but the problem is that you end up scattering all the related hosts in a domain:
a.me a.you b.me b.you
So, the basic logic I came up with reverse the order of the labels, then sort.
FQDNs of one label should be treated as hostnames, and probably sorted separately, maybe at the top.
Ideally I am looking for javascript and java versions.
I also don't know if this design works well for the newer internationalized domain names.
Has anyone implemented sorting a list of domain names?
I have seen some applications sort them as flat strings, but the problem is that you end up scattering all the related hosts in a domain:
a.me. a.you. b.me. b.you.
So, the basic logic I came up with reverse the order of the labels, then sort.
FQDNs of one label should be treated as hostnames, and probably sorted separately, maybe at the top.
Ideally I am looking for javascript and java versions.
I also don't know if this design works well for the newer internationalized domain names.
Share Improve this question asked Dec 5, 2008 at 1:00 munity wikibenc 0
7 Answers
Reset to default 2I don't know about Java and Javascript in particular, but many languages provide some sort of array data structure that can be lexicographically sorted. So, like you said, convert "a.example." into {"", "example", "a"}, and just let the default sorting rules run. A lexicographical sort will then do exactly what you want.
If you have a list of local domains as well as FQDNs, I agree you'd want to separate those out. Anything that doesn't have a period in it could be filtered out first. Or, you could resolve those all to FQDNs and then just sort the whole list.
Some Python code that does this (should map to Javascript fairly closely):
hosts = ["a.foo.", "b.foo.", "foo.", "c.bar."]
split_hosts = []
for h in hosts:
segments = h.split('.')
segments.reverse()
split_hosts.append(segments)
split_hosts.sort()
for segments in split_hosts:
segments.reverse()
print ".".join(segments)
This prints:
c.bar.
foo.
a.foo.
b.foo.
Based on Tom's answer...
hosts = new Array( "a.foo.", "b.foo.", "foo.", "c.bar." );
//print("Unsorted:");
//for (host in hosts )
// print(hosts[host]);
sorted_hosts = new Array();
split_hosts = new Array();
for(h in hosts)
{
segments = hosts[h].split('.');
segments.reverse();
split_hosts.push(segments);
}
split_hosts.sort()
for(h in split_hosts)
{
split_hosts[h].reverse()
sorted_hosts.push(split_hosts[h].join("."))
}
//print("Sorted:");
//for (host in sorted_hosts )
// print(sorted_hosts[host]);
The print statements work (when unmented) in the SquareFree JavaScript Development Environment, a handy place to test out javascript fragments...
This is a result of the big-endian vs little-endian war of the early 80s which the little-endian team won. In the UK, domain names were originally ordered like (the hypothetical) 'uk.ac.leeds' for the UK 'academic' (University of) Leeds. This is big-endian ordering - and makes your sort far easier. It would also make it far harder to spoof internet sites in URLs. Of course, nowadays, the order is little-endian, and the hypothetical URL would be 'leeds.ac.uk'.
To sort related domain names together sensibly, you will have to achieve the effect of sorting by furthest right ponent (., .uk, ) first, then the next left, and repeat... In other words (as @Bala said), you will have to do something similar to splitting the names up and sorting from right-to-left.
This is how it's done in Perl:
#!/usr/bin/perl -w
use strict;
my @hosts = qw(
bar
a.foo.
b.foo.
foo.
c.bar.
);
print join("\n", sort {
$a = lc($a);
$b = lc($b);
if ($a eq $b) {
return 0;
}
my @a = reverse(split(/\./, $a));
my @b = reverse(split(/\./, $b));
my $max = (scalar(@a), scalar(@b))[@a < @b];
for (my $i=0; $i < $max; $i++) {
if (($i < @a) && ($i < @b)) {
if (my $c = $a[$i] cmp $b[$i]) {
return $c;
}
}
else {
return scalar(@a) <=> scalar(@b);
}
}
return 0;
} @hosts) . "\n";
I came up with this solution that utilizes Array.prototype.sort() and ES6 generators:
function* reverseIterateParts(domain) {
let currentEnd = domain.length;
for (let index = currentEnd-1; index >= -1; index--) {
if (index == -1 || domain[index] == '.') {
yield domain.substring(index + 1, currentEnd);
currentEnd = index;
}
}
}
arrayOfDomainNames.sort((domainA, domainB) => {
let partsOfA = reverseIterateParts(domainA);
let partsOfB = reverseIterateParts(domainB);
while (true) {
let partA = partsOfA.next();
let partB = partsOfB.next();
if (partA.done) {
if (partB.done) {
return 0;
}
return -1;
}
if (partB.done) {
return 1;
}
if (partA.value > partB.value) {
return 1;
}
if (partA.value < partB.value) {
return -1;
}
}
});
Here is a sample of sorting domains in Golang:
func Test_SortDomain(t *testing.T) {
domains := []string{"a.", "b.", "a.a", "a", "b.a."}
slices.SortFunc(domains, CompareDomain)
assert.Equal(t, []string{"a.", "b.a.", "b.", "a", "a.a"}, domains)
}
func CompareDomain(a, b string) int {
partsA := strings.Split(a, ".")
slices.Reverse(partsA)
partsB := strings.Split(b, ".")
slices.Reverse(partsB)
return slices.Compare(partsA, partsB)
}
You may rewrite it to Java.
You could split the domain names into individual fields and do successive sorts. You can create a domain name object to have three fields and create a list of domain names to sort. For each of the three fields, do a sort. At the end, you have a sort list of domain names with related hosts together.