我正在尝试对字符串数组进行排序,我希望它们按数字排序。
问题在于我无法将数字转换为int 。
以下是代码:
string[] things= new string[] { "105", "101", "102", "103", "90" };
foreach (var thing in things.OrderBy(x => x))
{
Console.WriteLine(thing);
}
输出:101,102,103,105,90
我想:90,101,102,103,105
编辑: 输出不能是090,101,102 ......
将代码示例更新为“thing”而不是“sizes”。数组可以是这样的:
string[] things= new string[] { "paul", "bob", "lauren", "007", "90" };
这意味着它需要按字母顺序和数字排序:
007,90,bob,lauren,paul答案 0 :(得分:90)
将自定义比较器传递给OrderBy。 Enumerable.OrderBy将允许您指定您喜欢的任何比较器。
这是一种方法:
void Main()
{
string[] things= new string[] { "paul", "bob", "lauren", "007", "90", "101"};
foreach (var thing in things.OrderBy(x => x, new SemiNumericComparer()))
{
Console.WriteLine(thing);
}
}
public class SemiNumericComparer: IComparer<string>
{
public int Compare(string s1, string s2)
{
if (IsNumeric(s1) && IsNumeric(s2))
{
if (Convert.ToInt32(s1) > Convert.ToInt32(s2)) return 1;
if (Convert.ToInt32(s1) < Convert.ToInt32(s2)) return -1;
if (Convert.ToInt32(s1) == Convert.ToInt32(s2)) return 0;
}
if (IsNumeric(s1) && !IsNumeric(s2))
return -1;
if (!IsNumeric(s1) && IsNumeric(s2))
return 1;
return string.Compare(s1, s2, true);
}
public static bool IsNumeric(object value)
{
try {
int i = Convert.ToInt32(value.ToString());
return true;
}
catch (FormatException) {
return false;
}
}
}
答案 1 :(得分:79)
用零填充到相同的长度:
int maxlen = sizes.Max(x => x.Length);
sizes.OrderBy(x => x.PadLeft(maxlen, '0'));
答案 2 :(得分:67)
而且,这个怎么样......
string[] sizes = new string[] { "105", "101", "102", "103", "90" };
var size = from x in sizes
orderby x.Length, x
select x;
foreach (var p in size)
{
Console.WriteLine(p);
}
答案 3 :(得分:44)
值是一个字符串
List = List.OrderBy(c => c.Value.Length).ThenBy(c => c.Value).ToList();
作品
答案 4 :(得分:4)
我想如果它在字符串中有一些数字会更好。 希望它会有所帮助。
PS:我不确定性能或复杂的字符串值,但它的效果很好:
lorem ipsum
lorem ipsum 1
lorem ipsum 2
lorem ipsum 3
...
lorem ipsum 20
lorem ipsum 21
public class SemiNumericComparer : IComparer<string>
{
public int Compare(string s1, string s2)
{
int s1r, s2r;
var s1n = IsNumeric(s1, out s1r);
var s2n = IsNumeric(s2, out s2r);
if (s1n && s2n) return s1r - s2r;
else if (s1n) return -1;
else if (s2n) return 1;
var num1 = Regex.Match(s1, @"\d+$");
var num2 = Regex.Match(s2, @"\d+$");
var onlyString1 = s1.Remove(num1.Index, num1.Length);
var onlyString2 = s2.Remove(num2.Index, num2.Length);
if (onlyString1 == onlyString2)
{
if (num1.Success && num2.Success) return Convert.ToInt32(num1.Value) - Convert.ToInt32(num2.Value);
else if (num1.Success) return 1;
else if (num2.Success) return -1;
}
return string.Compare(s1, s2, true);
}
public bool IsNumeric(string value, out int result)
{
return int.TryParse(value, out result);
}
}
答案 5 :(得分:4)
您说您无法将数字转换为int,因为数组可以包含无法转换为int的元素,但尝试时没有任何害处:
string[] things = new string[] { "105", "101", "102", "103", "90", "paul", "bob", "lauren", "007", "90" };
Array.Sort(things, CompareThings);
foreach (var thing in things)
Debug.WriteLine(thing);
然后比较如下:
private static int CompareThings(string x, string y)
{
int intX, intY;
if (int.TryParse(x, out intX) && int.TryParse(y, out intY))
return intX.CompareTo(intY);
return x.CompareTo(y);
}
输出:007,90,90,101,102,103,105,鲍勃,劳伦,保罗
答案 6 :(得分:4)
试试这个
sizes.OrderBy(x => Convert.ToInt32(x)).ToList<string>();
注意: 当所有字符串都可以转换为int .....时,这将很有用。
答案 7 :(得分:3)
这似乎是一个奇怪的请求,值得一个奇怪的解决方案:
string[] sizes = new string[] { "105", "101", "102", "103", "90" };
foreach (var size in sizes.OrderBy(x => {
double sum = 0;
int position = 0;
foreach (char c in x.ToCharArray().Reverse()) {
sum += (c - 48) * (int)(Math.Pow(10,position));
position++;
}
return sum;
}))
{
Console.WriteLine(size);
}
答案 8 :(得分:2)
该网站讨论了字母数字排序,并将逻辑意义上的数字排序,而不是ASCII感。它还考虑了它周围的alphas:
http://www.dotnetperls.com/alphanumeric-sorting
示例:强>
代码如下:
class Program
{
static void Main(string[] args)
{
var arr = new string[]
{
"C:/TestB/333.jpg",
"11",
"C:/TestB/33.jpg",
"1",
"C:/TestA/111.jpg",
"111F",
"C:/TestA/11.jpg",
"2",
"C:/TestA/1.jpg",
"111D",
"22",
"111Z",
"C:/TestB/03.jpg"
};
Array.Sort(arr, new AlphaNumericComparer());
foreach(var e in arr) {
Console.WriteLine(e);
}
}
}
public class AlphaNumericComparer : IComparer
{
public int Compare(object x, object y)
{
string s1 = x as string;
if (s1 == null)
{
return 0;
}
string s2 = y as string;
if (s2 == null)
{
return 0;
}
int len1 = s1.Length;
int len2 = s2.Length;
int marker1 = 0;
int marker2 = 0;
// Walk through two the strings with two markers.
while (marker1 < len1 && marker2 < len2)
{
char ch1 = s1[marker1];
char ch2 = s2[marker2];
// Some buffers we can build up characters in for each chunk.
char[] space1 = new char[len1];
int loc1 = 0;
char[] space2 = new char[len2];
int loc2 = 0;
// Walk through all following characters that are digits or
// characters in BOTH strings starting at the appropriate marker.
// Collect char arrays.
do
{
space1[loc1++] = ch1;
marker1++;
if (marker1 < len1)
{
ch1 = s1[marker1];
}
else
{
break;
}
} while (char.IsDigit(ch1) == char.IsDigit(space1[0]));
do
{
space2[loc2++] = ch2;
marker2++;
if (marker2 < len2)
{
ch2 = s2[marker2];
}
else
{
break;
}
} while (char.IsDigit(ch2) == char.IsDigit(space2[0]));
// If we have collected numbers, compare them numerically.
// Otherwise, if we have strings, compare them alphabetically.
string str1 = new string(space1);
string str2 = new string(space2);
int result;
if (char.IsDigit(space1[0]) && char.IsDigit(space2[0]))
{
int thisNumericChunk = int.Parse(str1);
int thatNumericChunk = int.Parse(str2);
result = thisNumericChunk.CompareTo(thatNumericChunk);
}
else
{
result = str1.CompareTo(str2);
}
if (result != 0)
{
return result;
}
}
return len1 - len2;
}
}
答案 9 :(得分:2)
Jeff Paulsen给出的答案是正确的,但Comprarer
可以简化为:
public class SemiNumericComparer: IComparer<string>
{
public int Compare(string s1, string s2)
{
if (IsNumeric(s1) && IsNumeric(s2))
return Convert.ToInt32(s1) - Convert.ToInt32(s2)
if (IsNumeric(s1) && !IsNumeric(s2))
return -1;
if (!IsNumeric(s1) && IsNumeric(s2))
return 1;
return string.Compare(s1, s2, true);
}
public static bool IsNumeric(object value)
{
int result;
return Int32.TryParse(value, out result);
}
}
这是有效的,因为唯一检查Comparer
结果的是结果是大于,小于还是等于零。可以简单地从另一个值中减去这些值,而不必处理返回值。
同样,IsNumeric
方法不必使用try
- 块,并且可以从TryParse
中受益。
对于那些不确定的人:
此Comparer将对值进行排序,以便非数值始终附加到列表的末尾。如果在开始时想要它们,则必须交换第二个和第三个if
块。
答案 10 :(得分:1)
试试这个:
string[] things= new string[] { "105", "101", "102", "103", "90" };
int tmpNumber;
foreach (var thing in (things.Where(xx => int.TryParse(xx, out tmpNumber)).OrderBy(xx => int.Parse(xx))).Concat(things.Where(xx => !int.TryParse(xx, out tmpNumber)).OrderBy(xx => xx)))
{
Console.WriteLine(thing);
}
答案 11 :(得分:1)
public class NaturalSort: IComparer<string>
{
[DllImport("shlwapi.dll", CharSet = CharSet.Unicode)]
public static extern int StrCmpLogicalW(string x, string y);
public int Compare(string x, string y)
{
return StrCmpLogicalW(x, y);
}
}
arr = arr.OrderBy(x =&gt; x,new NaturalSort())。ToArray();
我需要它的原因是归档到一个文件名以数字开头的目录:
public static FileInfo[] GetFiles(string path)
{
return new DirectoryInfo(path).GetFiles()
.OrderBy(x => x.Name, new NaturalSort())
.ToArray();
}
答案 12 :(得分:0)
我的首选解决方案(如果所有字符串都只是数字):
set.seed(1)
X <- matrix(runif(100*200),nrow=100)
X <- apply(X,1,sort)
lattice::levelplot(X,contour=TRUE)
library(raster)
r <- raster(X)
z <- cut(r, seq(0, 1, 0.1))
p <- rasterToPolygons(z, dissolve=TRUE)
spplot(p)
答案 13 :(得分:0)
public class Test
{
public void TestMethod()
{
List<string> buyersList = new List<string>() { "5", "10", "1", "str", "3", "string" };
List<string> soretedBuyersList = null;
soretedBuyersList = new List<string>(SortedList(buyersList));
}
public List<string> SortedList(List<string> unsoredList)
{
return unsoredList.OrderBy(o => o, new SortNumericComparer()).ToList();
}
}
public class SortNumericComparer : IComparer<string>
{
public int Compare(string x, string y)
{
int xInt = 0;
int yInt = 0;
int result = -1;
if (!int.TryParse(x, out xInt))
{
result = 1;
}
if(int.TryParse(y, out yInt))
{
if(result == -1)
{
result = xInt - yInt;
}
}
else if(result == 1)
{
result = string.Compare(x, y, true);
}
return result;
}
}
答案 14 :(得分:0)
Try this out..
string[] things = new string[] { "paul", "bob", "lauren", "007", "90", "-10" };
List<int> num = new List<int>();
List<string> str = new List<string>();
for (int i = 0; i < things.Count(); i++)
{
int result;
if (int.TryParse(things[i], out result))
{
num.Add(result);
}
else
{
str.Add(things[i]);
}
}
现在对列表进行排序并将它们合并回来......
var strsort = from s in str
orderby s.Length
select s;
var numsort = from n in num
orderby n
select n;
for (int i = 0; i < things.Count(); i++)
{
if(i < numsort.Count())
things[i] = numsort.ElementAt(i).ToString();
else
things[i] = strsort.ElementAt(i - numsort.Count());
}
我只是想在这个有趣的问题上做出贡献......
答案 15 :(得分:0)
答案 16 :(得分:0)
简短的 IComparer 类示例。
代码:
public class CompareIntegerStrings : IComparer<string>
{
public int Compare(string x, string y)
{
if (int.TryParse(x, out int xOut) && int.TryParse(y, out int yOut))
return xOut.CompareTo(yOut);
else if (int.TryParse(x, out _))
return -1;
else if (int.TryParse(y, out _))
return 1;
else
return x.CompareTo(y);
}
}
在这个例子中
List<string> intStrings = new List<string> { "01","0022","abba", "11", "deep purple", "02", };
List<string> orderedIntStrings = intStrings.OrderBy(i=>i,new CompareIntegerStrings()).ToList();
有序列表orderedIntString是{"01","02","11","0022","abba","deep Purple"}。
答案 17 :(得分:-1)
尽管这是一个老问题,但我想提出一个解决方案:
string[] things= new string[] { "105", "101", "102", "103", "90" };
foreach (var thing in things.OrderBy(x => Int32.Parse(x) )
{
Console.WriteLine(thing);
}
Woha很简单吧? :d
答案 18 :(得分:-1)
namespace X
{
public class Utils
{
public class StrCmpLogicalComparer : IComparer<Projects.Sample>
{
[DllImport("Shlwapi.dll", CharSet = CharSet.Unicode)]
private static extern int StrCmpLogicalW(string x, string y);
public int Compare(Projects.Sample x, Projects.Sample y)
{
string[] ls1 = x.sample_name.Split("_");
string[] ls2 = y.sample_name.Split("_");
string s1 = ls1[0];
string s2 = ls2[0];
return StrCmpLogicalW(s1, s2);
}
}
}
}