23

I've a list of IP addresses as follows

192.168.1.5
69.52.220.44
10.152.16.23
192.168.3.10
192.168.1.4
192.168.2.1

I'm looking for such a way to sort this list to match the below order

10.152.16.23
69.52.220.44
192.168.1.4
192.168.1.5
192.168.2.1
Alex Aza
  • 76,499
  • 26
  • 155
  • 134
Cracker
  • 916
  • 2
  • 7
  • 16

5 Answers5

54

This might look as a hack, but it does exactly what you need:

var unsortedIps =
    new[]
    {
        "192.168.1.4",
        "192.168.1.5",
        "192.168.2.1",
        "10.152.16.23",
        "69.52.220.44"
    };

var sortedIps = unsortedIps
    .Select(Version.Parse)
    .OrderBy(arg => arg)
    .Select(arg => arg.ToString())
    .ToList();
Alex Aza
  • 76,499
  • 26
  • 155
  • 134
11

You can convert each IP address into an integer like so ...

69.52.220.44 =>

69 * 255 * 255 * 255 +
52 * 255 * 255 +
220 * 255 +
44

Then sort by the integer representation.

ColinE
  • 68,894
  • 15
  • 164
  • 232
  • 3
    By that computation `0.0.0.255` has same value as `0.0.1.0` where they should be different. The multiplier should be 256, not 255. See from Wikipedia: "For example, the quad-dotted IP address 192.0.2.235 represents the 32-bit decimal number 3221226219". `192.0.2.235` => `192*256*256*256 + 2*256 + 235` = 3221226219 indeed where if you use above formula you get `192*255*255*255 + 2*255 + 235` = 3183624745 – Patrick Mevzek Dec 19 '18 at 16:40
  • @PatrickMevzek is right. A byte has 256 values and you should multiply for the number of values, not the higher one. – Riwels Dec 31 '20 at 00:02
  • Make sure you use 32-bit unsigned ints! – thinkOfaNumber May 28 '21 at 05:33
2

You may find this function useful too.

public static class ExtensionMethods
{
  public static int CompareTo(this IPAddress x, IPAddress y)
  {
    var result = x.AddressFamily.CompareTo(y.AddressFamily);
    if (result != 0)
      return result;

    var xBytes = x.GetAddressBytes();
    var yBytes = y.GetAddressBytes();

    var octets = Math.Min(xBytes.Length, yBytes.Length);
    for (var i = 0; i < octets; i++)
    {
      var octetResult = xBytes[i].CompareTo(yBytes[i]);
      if (octetResult != 0)
        return octetResult;
    }
    return 0;
  }
}
Ryan Williams
  • 1,465
  • 15
  • 19
2

No hackery required for a simple solution. Just Split() the address segments, pad the segments with zeros, and then join them back together. Put this one line static method into a static class like this:

public static class StringHelper
{
    public static string IpAddressLabel(string ipAddress)
        => string.Join(".", ipAddress.Split('.').Select(part => part.PadLeft(3, '0')));
}

And then call it at will:

 => new[] {"192.168.1.100", "192.168.1.1", "192.168.1.19"}
      .OrderBy(ip => StringHelper.IpAddressLabel(ip));

Also, this can be used as a filename or elsewhere when a sortable label is desired:

192.168.001.001.log
192.168.001.019.log
192.168.001.100.log
threadster
  • 418
  • 5
  • 18
0

You can use the Array.Sort function with a function we will create for comparing two IPs:

//ips is string array
Array.Sort(ips, IpCompare);

And then put this function in the code.

private static int IpCompare(string x, string y)
    {
        string ip1 = x + '.', ip2 = y + '.';
        string xSection = "", ySection = "";
        for (int i = 0; i < ip1.Length && i < ip2.Length; i++)
        {
            if (ip1[i] == '.' && ip2[i] == '.')
            {
                if (xSection != ySection)
                    return int.Parse(xSection) - int.Parse(ySection);
                xSection = ""; // Start compare the next section
                ySection = "";
            }
            else if (ip1[i] == '.') return -1; //The first section is smaller because it's length is smaller
            else if (ip2[i] == '.') return 1;
            else
            {
                xSection += ip1[i];
                ySection += ip2[i];
            }
        }
        return 0; 
        //If we would find any difference between any section it would already return something.
        //so that mean that both IPs are the same
   }
Dor Meiri
  • 389
  • 1
  • 4
  • 13