C# 排序列表<;字符串>;在C中#
如何根据项目的整数值对列表进行排序 清单如下C# 排序列表<;字符串>;在C中#,c#,natural-sort,C#,Natural Sort,如何根据项目的整数值对列表进行排序 清单如下 "1" "5" "3" "6" "11" "9" "NUM1" "NUM0" 结果应该是这样的 "1" "3" "5" "6" "9" "11" "NUM0" "NUM1" 使用LINQ或Lambda表达式可以实现这一点吗 提前感谢我认为除了listName.Sort()之外,您不需要任何东西,因为Sort()方法使用默认的比较器来快速排序节点。默认比较器正是您感兴趣的功能。如何: list.Sort((x, y) => {
"1"
"5"
"3"
"6"
"11"
"9"
"NUM1"
"NUM0"
结果应该是这样的
"1"
"3"
"5"
"6"
"9"
"11"
"NUM0"
"NUM1"
使用LINQ或Lambda表达式可以实现这一点吗
提前感谢我认为除了listName.Sort()之外,您不需要任何东西,因为Sort()方法使用默认的比较器来快速排序节点。默认比较器正是您感兴趣的功能。如何:
list.Sort((x, y) =>
{
int ix, iy;
return int.TryParse(x, out ix) && int.TryParse(y, out iy)
? ix.CompareTo(iy) : string.Compare(x, y);
});
这称为“自然排序顺序”,通常用于对文件名等项目进行排序
下面是一个幼稚的实现(从某种意义上说,它可能有很多unicode问题),它似乎做到了这一点:
您可以将下面的代码复制到中来执行和测试它
基本上,比较算法将识别字符串中的数字,并通过用前导零填充最短的数字来处理这些数字,因此,例如,两个字符串“Test123Abc”
和“Test7X”
应该像比较“Test123Abc”
和“Test007X”
一样进行比较,这会产生你想要的
然而,当我说“幼稚”时,我的意思是我可能在这里有很多真正的unicode问题,比如处理变音符号和多码点字符。如果有人能提供更好的实现,我很乐意看到它
注:
- 该实现实际上并不解析数字,因此任意长的数字应该可以正常工作
- 由于它实际上没有将数字解析为“数字”,因此浮点数字将无法正确处理,“123.45”与“123.789”将被比较为“123.045”与“123.789”,这是错误的
void Main()
{
列表输入=新列表
{
“1”、“5”、“3”、“6”、“11”、“9”、“A1”、“A0”
};
var output=input.NaturalSort();
output.Dump();
}
公共静态类扩展
{
公共静态IEnumerable NaturalSort(
这是我的收藏)
{
返回NaturalSort(集合,CultureInfo.CurrentCulture);
}
公共静态IEnumerable NaturalSort(
此IEnumerable集合(CultureInfo CultureInfo)
{
return collection.OrderBy(s=>s,新的自然比较程序(cultureInfo));
}
私人类自然比较者:IComparer
{
私有只读文化信息(CultureInfo);;
公共自然比较(CultureInfo CultureInfo)
{
_CultureInfo=CultureInfo;
}
公共整数比较(字符串x、字符串y)
{
//简单案例
if(x==y)//也处理null
返回0;
如果(x==null)
返回-1;
如果(y==null)
返回+1;
int ix=0;
int-iy=0;
而(ix
杰夫·阿特伍德(Jeff Atwood)有一篇关于自然排序的文章,他在文章中链接到了所需算法的一些可用实现
Jeffs的其中一个链接指向如何拥有:
/*
*Alphanum算法是一种改进的字符串排序算法
*包含数字。而不是像这样按ASCII顺序对数字进行排序
*作为一种标准排序,该算法按数字顺序对数字进行排序。
*
*Alphanum算法在http://www.DaveKoelle.com
*
*基于Dave Koelle的Alphanum算法的Java实现。
*乔纳森·拉克伍德撰稿
*
*由Dominik Hurnaus改编为
*-正确排序一个单词以另一个单词开头的单词
*-性能稍好
*
*根据麻省理工学院许可证发布-https://opensource.org/licenses/MIT
*
*特此免费向获得许可的任何人授予许可
*本软件及相关文档文件(“软件”)的副本,
*不受限制地处理软件,包括但不限于
*使用、复制、修改、合并、发布、分发、再许可、,
*和/或出售软件副本,并允许
*为此提供的软件应符合以下条件:
*
*应包括上述版权声明和本许可声明
*在
void Main()
{
List<string> input = new List<string>
{
"1", "5", "3", "6", "11", "9", "A1", "A0"
};
var output = input.NaturalSort();
output.Dump();
}
public static class Extensions
{
public static IEnumerable<string> NaturalSort(
this IEnumerable<string> collection)
{
return NaturalSort(collection, CultureInfo.CurrentCulture);
}
public static IEnumerable<string> NaturalSort(
this IEnumerable<string> collection, CultureInfo cultureInfo)
{
return collection.OrderBy(s => s, new NaturalComparer(cultureInfo));
}
private class NaturalComparer : IComparer<string>
{
private readonly CultureInfo _CultureInfo;
public NaturalComparer(CultureInfo cultureInfo)
{
_CultureInfo = cultureInfo;
}
public int Compare(string x, string y)
{
// simple cases
if (x == y) // also handles null
return 0;
if (x == null)
return -1;
if (y == null)
return +1;
int ix = 0;
int iy = 0;
while (ix < x.Length && iy < y.Length)
{
if (Char.IsDigit(x[ix]) && Char.IsDigit(y[iy]))
{
// We found numbers, so grab both numbers
int ix1 = ix++;
int iy1 = iy++;
while (ix < x.Length && Char.IsDigit(x[ix]))
ix++;
while (iy < y.Length && Char.IsDigit(y[iy]))
iy++;
string numberFromX = x.Substring(ix1, ix - ix1);
string numberFromY = y.Substring(iy1, iy - iy1);
// Pad them with 0's to have the same length
int maxLength = Math.Max(
numberFromX.Length,
numberFromY.Length);
numberFromX = numberFromX.PadLeft(maxLength, '0');
numberFromY = numberFromY.PadLeft(maxLength, '0');
int comparison = _CultureInfo
.CompareInfo.Compare(numberFromX, numberFromY);
if (comparison != 0)
return comparison;
}
else
{
int comparison = _CultureInfo
.CompareInfo.Compare(x, ix, 1, y, iy, 1);
if (comparison != 0)
return comparison;
ix++;
iy++;
}
}
// we should not be here with no parts left, they're equal
Debug.Assert(ix < x.Length || iy < y.Length);
// we still got parts of x left, y comes first
if (ix < x.Length)
return +1;
// we still got parts of y left, x comes first
return -1;
}
}
}
/*
* The Alphanum Algorithm is an improved sorting algorithm for strings
* containing numbers. Instead of sorting numbers in ASCII order like
* a standard sort, this algorithm sorts numbers in numeric order.
*
* The Alphanum Algorithm is discussed at http://www.DaveKoelle.com
*
* Based on the Java implementation of Dave Koelle's Alphanum algorithm.
* Contributed by Jonathan Ruckwood <jonathan.ruckwood@gmail.com>
*
* Adapted by Dominik Hurnaus <dominik.hurnaus@gmail.com> to
* - correctly sort words where one word starts with another word
* - have slightly better performance
*
* Released under the MIT License - https://opensource.org/licenses/MIT
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
using System;
using System.Collections;
using System.Text;
/*
* Please compare against the latest Java version at http://www.DaveKoelle.com
* to see the most recent modifications
*/
namespace AlphanumComparator
{
public class AlphanumComparator : IComparer
{
private enum ChunkType {Alphanumeric, Numeric};
private bool InChunk(char ch, char otherCh)
{
ChunkType type = ChunkType.Alphanumeric;
if (char.IsDigit(otherCh))
{
type = ChunkType.Numeric;
}
if ((type == ChunkType.Alphanumeric && char.IsDigit(ch))
|| (type == ChunkType.Numeric && !char.IsDigit(ch)))
{
return false;
}
return true;
}
public int Compare(object x, object y)
{
String s1 = x as string;
String s2 = y as string;
if (s1 == null || s2 == null)
{
return 0;
}
int thisMarker = 0, thisNumericChunk = 0;
int thatMarker = 0, thatNumericChunk = 0;
while ((thisMarker < s1.Length) || (thatMarker < s2.Length))
{
if (thisMarker >= s1.Length)
{
return -1;
}
else if (thatMarker >= s2.Length)
{
return 1;
}
char thisCh = s1[thisMarker];
char thatCh = s2[thatMarker];
StringBuilder thisChunk = new StringBuilder();
StringBuilder thatChunk = new StringBuilder();
while ((thisMarker < s1.Length) && (thisChunk.Length==0 ||InChunk(thisCh, thisChunk[0])))
{
thisChunk.Append(thisCh);
thisMarker++;
if (thisMarker < s1.Length)
{
thisCh = s1[thisMarker];
}
}
while ((thatMarker < s2.Length) && (thatChunk.Length==0 ||InChunk(thatCh, thatChunk[0])))
{
thatChunk.Append(thatCh);
thatMarker++;
if (thatMarker < s2.Length)
{
thatCh = s2[thatMarker];
}
}
int result = 0;
// If both chunks contain numeric characters, sort them numerically
if (char.IsDigit(thisChunk[0]) && char.IsDigit(thatChunk[0]))
{
thisNumericChunk = Convert.ToInt32(thisChunk.ToString());
thatNumericChunk = Convert.ToInt32(thatChunk.ToString());
if (thisNumericChunk < thatNumericChunk)
{
result = -1;
}
if (thisNumericChunk > thatNumericChunk)
{
result = 1;
}
}
else
{
result = thisChunk.ToString().CompareTo(thatChunk.ToString());
}
if (result != 0)
{
return result;
}
}
return 0;
}
}
}
public class NameAndNumber
{
public NameAndNumber(string s)
{
OriginalString = s;
Match match = Regex.Match(s,@"^(.*?)(\d*)$");
Name = match.Groups[1].Value;
int number;
int.TryParse(match.Groups[2].Value, out number);
Number = number; //will get default value when blank
}
public string OriginalString { get; private set; }
public string Name { get; private set; }
public int Number { get; private set; }
}
var list = new List<string> { "ABC", "1", "5", "NUM44", "3",
"6", "11", "9", "NUM1", "NUM0" };
var sorted = list.Select(str => new NameAndNumber(str))
.OrderBy(n => n.Name)
.ThenBy(n => n.Number);
static void Sort()
{
string[] partNumbers = new string[] {"A1", "A2", "A10", "A111"};
string[] result = partNumbers.OrderBy(x => PadNumbers(x)).ToArray();
}
public static string PadNumbers(string input)
{
const int MAX_NUMBER_LEN = 10;
string newInput = "";
string currentNumber = "";
foreach (char a in input)
{
if (!char.IsNumber(a))
{
if (currentNumber == "")
{
newInput += a;
continue;
}
newInput += "0000000000000".Substring(0, MAX_NUMBER_LEN - currentNumber.Length) + currentNumber;
currentNumber = "";
}
currentNumber += a;
}
if (currentNumber != "")
{
newInput += "0000000000000".Substring(0, MAX_NUMBER_LEN - currentNumber.Length) + currentNumber;
}
return newInput;
}
var numericList = a.Where(i => int.TryParse(i, out _)).OrderBy(j => int.Parse(j)).ToList();
var nonNumericList = a.Where(i => !int.TryParse(i, out _)).OrderBy(j => j).ToList();
a.Clear();
a.AddRange(numericList);
a.AddRange(nonNumericList);