How to sort list of Ip Addresses using c#
Asked Answered
M

6

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
Maurine answered 6/6, 2011 at 5:16 Comment(0)
E
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();
Equipotential answered 6/6, 2011 at 5:22 Comment(9)
This will give you "10.152.16.23","192.168.1.4", "192.168.1.5", "192.168.2.1", "69.52.220.44"Orosco
@Orosco - please try the code before stating that. I actually checked the result before posting.Equipotential
@Alex nice solution, thnx ManMaurine
@Alex that's actually a brilliant idea, thanks, it saved me timePhooey
A more compact version: unsortedIps.OrderBy(Version.Parse).ToList().Marlanamarlane
Just a note that the Version.Parse method was only added in .Net Framework 4, so if using an earlier version of the framework this solution will not work.Practicable
System.Net.IPAddress.Parse is something that we can try in place of Version.ParseBatson
I had a List<IPAddress> and sorted it like this: lstIp = lstIp.OrderBy(i => new Version(i.ToString())).ToList();Eatables
Can be much simpler: sortedIps = unsortedIps.OrderBy(ip => Version.Parse(ip)).ToList();Lemley
F
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.

Fruiter answered 6/6, 2011 at 5:23 Comment(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 = 3183624745Ascetic
@PatrickMevzek is right. A byte has 256 values and you should multiply for the number of values, not the higher one.Morocco
Make sure you use 32-bit unsigned ints!Theoretical
O
3

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;
  }
}
Odoacer answered 14/9, 2016 at 5:8 Comment(0)
R
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
Ruinous answered 14/12, 2020 at 17:33 Comment(0)
R
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
   }
Rambutan answered 7/9, 2018 at 10:37 Comment(0)
U
0
    [HttpGet("[action]")]
    public IActionResult GetAll(bool? Sort, IP_Version? Type, string? CIDR, string? SearchIP)
    {
        var query = _context.IPs.AsEnumerable();

        if (Sort != null)
            if (Sort.Value)
            {
                query = Type == IP_Version.IPV4 ?
                        query.OrderBy(x => x.Type).ThenBy(x => int.Parse(x.Ip.ToString().Replace(".", ""))) :
                        query.OrderBy(x => x.Type).ThenBy(x => x.Ip);

            }
            else
                query = Type == IP_Version.IPV4 ?
                    query.OrderBy(x => x.Type).ThenByDescending(x => int.Parse(x.Ip.ToString().Replace(".", ""))) :
                    query.OrderBy(x => x.Type).ThenByDescending(x => x.Ip);

        if (Type != null)
            query = query.Where(x => x.Type == Type);

        if (SearchIP != null)
            query = query.Where(x => x.Ip.StartsWith(SearchIP.ToLower()));

        var res = query.Select(x => new IPDto() { Ip = x.Ip, Type = x.Type.ToString() }).ToList();

        return Ok(res);
    }
Unready answered 12/7 at 8:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.