给定List<string> ips = new List<string>();
我需要按逻辑顺序对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
答案 0 :(得分:18)
您需要制作一个比较器:(已测试)
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())
答案 1 :(得分:6)
我会为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());
答案 2 :(得分:2)
您可以将其拆分为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) );
答案 3 :(得分:2)
这个非常优雅(如果使用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
数组的长度为4,只要它是IP4地址即可。否则你应该考虑长度......
答案 4 :(得分:1)
我写了一个IPv6的IpComparer。 Howel的变种不起作用。
这是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);
}
}
这是一个单元测试:
[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的专家。
答案 5 :(得分:0)
这是一个老问题,但我正在查找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));
}
}
没有什么花哨但它应该有效。