List的 Linq/Lambda OrderBy 委托IP 地址数

发布于 2024-10-14 04:30:47 字数 366 浏览 4 评论 0原文

给定 List; ips = new List();

我需要按逻辑顺序对 IP 地址列表进行排序(即“192.168.0.2”位于“192.168.0.100”之前)。

当前(正确地,按字母顺序)如果列表包含:

192.168.0.1
192.168.0.2
192.168.0.10
192.168.0.200

ips.OrderBy(p => p) 则返回:

192.168.0.1
192.168.0.10
192.168.0.2
192.168.0.200

Given List<string> ips = new List<string>();

I need to sort the list of IP addresses in a logical order (i.e. "192.168.0.2" comes before "192.168.0.100").

Currently (and correctly, alphabetically) if the list contains:

192.168.0.1
192.168.0.2
192.168.0.10
192.168.0.200

ips.OrderBy(p => p) returns:

192.168.0.1
192.168.0.10
192.168.0.2
192.168.0.200

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

江城子 2024-10-21 04:30:47

您需要制作一个比较器:(已测试)

class IPComparer : IComparer<string> {
    public int Compare(string a, string b) {
        return Enumerable.Zip(a.Split('.'), b.Split('.'), 
                             (x, y) => int.Parse(x).CompareTo(int.Parse(y)))
                         .FirstOrDefault(i => i != 0); 
    }
}

然后您可以编写

ips.OrderBy(p => p, new IPComparer()) 

You need to make a comparer: (Tested)

class IPComparer : IComparer<string> {
    public int Compare(string a, string b) {
        return Enumerable.Zip(a.Split('.'), b.Split('.'), 
                             (x, y) => int.Parse(x).CompareTo(int.Parse(y)))
                         .FirstOrDefault(i => i != 0); 
    }
}

You can then write

ips.OrderBy(p => p, new IPComparer()) 
亽野灬性zι浪 2024-10-21 04:30:47

我会像这样为 System.Net.IPAddress 创建一个比较器

class IPAddressComparer : IComparer<IPAddress> {
    public int Compare(IPAddress x, IPAddress y) {
        byte[] first = x.GetAddressBytes();
        byte[] second = y.GetAddressBytes();
        return first.Zip(second, (a, b) => a.CompareTo(b))
                    .FirstOrDefault(c => c != 0);
    }   
}

,然后按以下步骤操作:

var list = new List<string>() {
    "192.168.0.1",
    "192.168.0.10",
    "192.168.0.2",
    "192.168.0.200"
};
var sorted = list.OrderBy(s => IPAddress.Parse(s), new IPAddressComparer());

I would create a comparer for System.Net.IPAddress like so

class IPAddressComparer : IComparer<IPAddress> {
    public int Compare(IPAddress x, IPAddress y) {
        byte[] first = x.GetAddressBytes();
        byte[] second = y.GetAddressBytes();
        return first.Zip(second, (a, b) => a.CompareTo(b))
                    .FirstOrDefault(c => c != 0);
    }   
}

and then proceed as follows:

var list = new List<string>() {
    "192.168.0.1",
    "192.168.0.10",
    "192.168.0.2",
    "192.168.0.200"
};
var sorted = list.OrderBy(s => IPAddress.Parse(s), new IPAddressComparer());
简单爱 2024-10-21 04:30:47

您可以将其拆分为 4 个整数值,然后按每个整数值依次排序:

 var results = ips
       .Select(s => string.Split('.').Select(str => int.Parse(str)).ToArray() )
       .OrderBy(intArray => intArray[0])
       .ThenBy(intArray => intArray[1])
       .ThenBy(intArray => intArray[2])
       .ThenBy(intArray => intArray[3])
       .Select(intArray => string.Join(".", intArray) );

You could split this into 4 integer values, and sort by each in turn:

 var results = ips
       .Select(s => string.Split('.').Select(str => int.Parse(str)).ToArray() )
       .OrderBy(intArray => intArray[0])
       .ThenBy(intArray => intArray[1])
       .ThenBy(intArray => intArray[2])
       .ThenBy(intArray => intArray[3])
       .Select(intArray => string.Join(".", intArray) );
你是年少的欢喜 2024-10-21 04:30:47

这个非常优雅(如果您使用 TryParse,并且可以防止失败):

var sorted2 = from ip in ips
              let addressBytes = IPAddress.Parse(ip).GetAddressBytes()
              orderby addressBytes[0], addressBytes[1], addressBytes[2], addressBytes[3]
              select ip;

只要 addressBytes 数组只是 IP4 地址,它的长度就为 4。否则你应该考虑长度......

This one is pretty elegant (and fail proof if you use TryParse):

var sorted2 = from ip in ips
              let addressBytes = IPAddress.Parse(ip).GetAddressBytes()
              orderby addressBytes[0], addressBytes[1], addressBytes[2], addressBytes[3]
              select ip;

The addressBytes array will have length 4 as long as it is only IP4 addresses. Otherwise you should account for the length...

罪#恶を代价 2024-10-21 04:30:47

我为 IPv6 编写了一个 IpComparer。 Howel 的变体不起作用。

这是比较器:

/// <summary>
/// Compares two ip addresses.
/// http://stackoverflow.com/questions/4785218/linq-lambda-orderby-delegate-for-liststring-of-ip-addresses
/// </summary>
public class IpComparer : IComparer<IPAddress>
{
    /// <summary>
    /// Compares two objects and returns a value indicating whether one is less than, equal to, or greater than the other.
    /// </summary>
    /// 
    /// <returns>
    /// A signed integer that indicates the relative values of <paramref name="x"/> and <paramref name="y"/>, as shown in the following table.
    /// Value Meaning Less than zero<paramref name="x"/> is less than <paramref name="y"/>.
    /// Zero<paramref name="x"/> equals <paramref name="y"/>.
    /// Greater than zero <paramref name="x"/> is greater than <paramref name="y"/>.
    /// </returns>
    /// <param name="x">The first object to compare.</param><param name="y">The second object to compare.</param>
    public int Compare(IPAddress x, IPAddress y)
    {
        if (ReferenceEquals(x, null))
        {
            throw new ArgumentNullException("x");
        }

        if (ReferenceEquals(y, null))
        {
            throw new ArgumentNullException("y");
        }

        byte[] bytesOfX = x.GetAddressBytes();
        byte[] bytesOfY = y.GetAddressBytes();

        return StructuralComparisons.StructuralComparer.Compare(bytesOfX, bytesOfY);
    }
}

这是一个单元测试:

[TestFixture]
public class IpComparerTest : AbstractUnitTest
{
    private IpComparer _testee;

    [SetUp]
    public void Setup()
    {
        _testee = new IpComparer();
    }

    [TestCase("10.156.35.205", "10.156.35.205")]
    [TestCase("0.0.0.1", "0.0.0.1")]
    [TestCase("2001:0db8:0000:08d3:0000:8a2e:0070:7344", "2001:db8:0:8d3:0:8a2e:70:7344")]
    [TestCase("2001:0db8:0:0:0:0:1428:57ab", "2001:db8::1428:57ab")]
    [TestCase("2001:0db8:0:0:8d3:0:0:0", "2001:db8:0:0:8d3::")]
    [TestCase("::ffff:127.0.0.1", "::ffff:7f00:1")]
    public void Compare_WhenIpsAreEqual_ThenResultIsZero(string ip1, string ip2)
    {
        // Arrange
        IPAddress x = IPAddress.Parse(ip1);
        IPAddress y = IPAddress.Parse(ip2);

        // Act and Assert
        Assert.That(_testee.Compare(x, y), Is.EqualTo(0));
    }

    [TestCase("10.156.35.2", "10.156.35.205")]
    [TestCase("0.0.0.0", "0.0.0.1")]
    [TestCase("1001:0db8:85a3:08d3:1319:8a2e:0370:7344", "2001:0db8:85a3:08d3:1319:8a2e:0370:7344")]
    [TestCase("2001:0db8:85a3:08d3:1319:8a2e:0370:7343", "2001:0db8:85a3:08d3:1319:8a2e:0370:7344")]
    public void Compare_WhenIp1IsLessThanIp2_ThenResultIsLessThanZero(string ip1, string ip2)
    {
        // Arrange
        IPAddress x = IPAddress.Parse(ip1);
        IPAddress y = IPAddress.Parse(ip2);

        // Act and Assert
        Assert.That(_testee.Compare(x, y), Is.LessThan(0));
    }

    [TestCase("10.156.35.205", "10.156.35.2")]
    [TestCase("0.0.0.1", "0.0.0.0")]
    [TestCase("3001:0db8:85a3:08d3:1319:8a2e:0370:7344", "2001:0db8:85a3:08d3:1319:8a2e:0370:7344")]
    [TestCase("2001:0db8:85a3:08d3:1319:8a2e:0370:7345", "2001:0db8:85a3:08d3:1319:8a2e:0370:7344")]
    public void Compare_WhenIp1IsGreaterThanIp2_ThenResultIsGreaterThanZero(string ip1, string ip2)
    {
        // Arrange
        IPAddress x = IPAddress.Parse(ip1);
        IPAddress y = IPAddress.Parse(ip2);

        // Act and Assert
        Assert.That(_testee.Compare(x, y), Is.GreaterThan(0));
    }
}

我希望这个解决方案是正确的。我不是 IPv6 方面的专家。

I wrote an IpComparer for IPv6. The variant from Howel doesn't work.

Here is the Comparer:

/// <summary>
/// Compares two ip addresses.
/// http://stackoverflow.com/questions/4785218/linq-lambda-orderby-delegate-for-liststring-of-ip-addresses
/// </summary>
public class IpComparer : IComparer<IPAddress>
{
    /// <summary>
    /// Compares two objects and returns a value indicating whether one is less than, equal to, or greater than the other.
    /// </summary>
    /// 
    /// <returns>
    /// A signed integer that indicates the relative values of <paramref name="x"/> and <paramref name="y"/>, as shown in the following table.
    /// Value Meaning Less than zero<paramref name="x"/> is less than <paramref name="y"/>.
    /// Zero<paramref name="x"/> equals <paramref name="y"/>.
    /// Greater than zero <paramref name="x"/> is greater than <paramref name="y"/>.
    /// </returns>
    /// <param name="x">The first object to compare.</param><param name="y">The second object to compare.</param>
    public int Compare(IPAddress x, IPAddress y)
    {
        if (ReferenceEquals(x, null))
        {
            throw new ArgumentNullException("x");
        }

        if (ReferenceEquals(y, null))
        {
            throw new ArgumentNullException("y");
        }

        byte[] bytesOfX = x.GetAddressBytes();
        byte[] bytesOfY = y.GetAddressBytes();

        return StructuralComparisons.StructuralComparer.Compare(bytesOfX, bytesOfY);
    }
}

And here a unit test:

[TestFixture]
public class IpComparerTest : AbstractUnitTest
{
    private IpComparer _testee;

    [SetUp]
    public void Setup()
    {
        _testee = new IpComparer();
    }

    [TestCase("10.156.35.205", "10.156.35.205")]
    [TestCase("0.0.0.1", "0.0.0.1")]
    [TestCase("2001:0db8:0000:08d3:0000:8a2e:0070:7344", "2001:db8:0:8d3:0:8a2e:70:7344")]
    [TestCase("2001:0db8:0:0:0:0:1428:57ab", "2001:db8::1428:57ab")]
    [TestCase("2001:0db8:0:0:8d3:0:0:0", "2001:db8:0:0:8d3::")]
    [TestCase("::ffff:127.0.0.1", "::ffff:7f00:1")]
    public void Compare_WhenIpsAreEqual_ThenResultIsZero(string ip1, string ip2)
    {
        // Arrange
        IPAddress x = IPAddress.Parse(ip1);
        IPAddress y = IPAddress.Parse(ip2);

        // Act and Assert
        Assert.That(_testee.Compare(x, y), Is.EqualTo(0));
    }

    [TestCase("10.156.35.2", "10.156.35.205")]
    [TestCase("0.0.0.0", "0.0.0.1")]
    [TestCase("1001:0db8:85a3:08d3:1319:8a2e:0370:7344", "2001:0db8:85a3:08d3:1319:8a2e:0370:7344")]
    [TestCase("2001:0db8:85a3:08d3:1319:8a2e:0370:7343", "2001:0db8:85a3:08d3:1319:8a2e:0370:7344")]
    public void Compare_WhenIp1IsLessThanIp2_ThenResultIsLessThanZero(string ip1, string ip2)
    {
        // Arrange
        IPAddress x = IPAddress.Parse(ip1);
        IPAddress y = IPAddress.Parse(ip2);

        // Act and Assert
        Assert.That(_testee.Compare(x, y), Is.LessThan(0));
    }

    [TestCase("10.156.35.205", "10.156.35.2")]
    [TestCase("0.0.0.1", "0.0.0.0")]
    [TestCase("3001:0db8:85a3:08d3:1319:8a2e:0370:7344", "2001:0db8:85a3:08d3:1319:8a2e:0370:7344")]
    [TestCase("2001:0db8:85a3:08d3:1319:8a2e:0370:7345", "2001:0db8:85a3:08d3:1319:8a2e:0370:7344")]
    public void Compare_WhenIp1IsGreaterThanIp2_ThenResultIsGreaterThanZero(string ip1, string ip2)
    {
        // Arrange
        IPAddress x = IPAddress.Parse(ip1);
        IPAddress y = IPAddress.Parse(ip2);

        // Act and Assert
        Assert.That(_testee.Compare(x, y), Is.GreaterThan(0));
    }
}

I hope this solution is correct. I'm not an expert in IPv6.

昔梦 2024-10-21 04:30:47

这是一个老问题,但我在查找 IP Comparer 时发现了这个问题。我想要一些也适用于 IPv6 的东西,所以一旦我得到它,我想我会将它添加到这里,以便下一个搜索它的人。就像 SLAks 的回答一样,我同意 IComparer 可能是最好的。

public class IPComparer : IComparer<IPAddress>
{
    public int Compare(IPAddress x, IPAddress y)
    {
        if (ReferenceEquals(x, null))
            throw new ArgumentNullException("x");

        if (ReferenceEquals(y, null))
            throw new ArgumentNullException("y");

        return BitConverter.ToUInt32(x.GetAddressBytes().Reverse().ToArray(),0)
            .CompareTo(BitConverter.ToUInt32(y.GetAddressBytes().Reverse().ToArray(),0));
    }
}

没什么特别的,但应该可以。

This is an old question but I was looking up IP Comparer's and it came up. I wanted something that worked for IPv6 as well though so once I got it I thought I'd add it here for the next person who does a search for it. Much like SLaks's answer, I agree that an IComparer is probably best.

public class IPComparer : IComparer<IPAddress>
{
    public int Compare(IPAddress x, IPAddress y)
    {
        if (ReferenceEquals(x, null))
            throw new ArgumentNullException("x");

        if (ReferenceEquals(y, null))
            throw new ArgumentNullException("y");

        return BitConverter.ToUInt32(x.GetAddressBytes().Reverse().ToArray(),0)
            .CompareTo(BitConverter.ToUInt32(y.GetAddressBytes().Reverse().ToArray(),0));
    }
}

Nothing fancy but it should work.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文