当字符串为数字时,如何在按值排序时按字母顺序对字符串进行排序?

| 我正在尝试对一组数字进行排序,这些数字是字符串,我希望它们能够按数字进行排序。 问题是我无法将数字转换为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 ... 更新了代码示例,使之改为\“ things \”,而不是\“ sizes \”。该数组可以是这样的:
string[] things= new string[] { \"paul\", \"bob\", \"lauren\", \"007\", \"90\" };
这意味着它需要按字母顺序和数字排序: 007、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>
{
    /// <summary>
    /// Method to determine if a string is a number
    /// </summary>
    /// <param name=\"value\">String to test</param>
    /// <returns>True if numeric</returns>
    public static bool IsNumeric(string value)
    {
        return int.TryParse(value, out _);
    }

    /// <inheritdoc />
    public int Compare(string s1, string s2)
    {
        const int S1GreaterThanS2 = 1;
        const int S2GreaterThanS1 = -1;

        var IsNumeric1 = IsNumeric(s1);
        var IsNumeric2 = IsNumeric(s2);

        if (IsNumeric1 && IsNumeric2)
        {
            var i1 = Convert.ToInt32(s1);
            var i2 = Convert.ToInt32(s2);

            if (i1 > i2)
            {
                return S1GreaterThanS2;
            }

            if (i1 < i2)
            {
                return S2GreaterThanS1;
            }

            return 0;
        }

        if (IsNumeric1)
        {
            return S2GreaterThanS1;
        }

        if (IsNumeric2)
        {
            return S1GreaterThanS2;
        }

        return string.Compare(s1, s2, true, CultureInfo.InvariantCulture);
    }
}
    
        只需填充零到相同的长度:
int maxlen = sizes.Max(x => x.Length);
sizes.OrderBy(x => x.PadLeft(maxlen, \'0\'));
    
        而且,如何...
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);
}
    
        值是一个字符串
List = List.OrderBy(c => c.Value.Length).ThenBy(c => c.Value).ToList();
作品     
        Windows
StrCmpLogicalW
中有一个本机函数,它将字符串中的数字作为数字而不是字母进行比较。使比较器很容易调用该函数并将其用于比较。
public class StrCmpLogicalComparer : Comparer<string>
{
    [DllImport(\"Shlwapi.dll\", CharSet = CharSet.Unicode)]
    private static extern int StrCmpLogicalW(string x, string y);

    public override int Compare(string x, string y)
    {
        return StrCmpLogicalW(x, y);
    }
}
它甚至适用于同时具有文本和数字的字符串。这是一个示例程序,它将显示默认排序和and6ѭ排序之间的差异
class Program
{
    static void Main()
    {
        List<string> items = new List<string>()
        {
            \"Example1.txt\", \"Example2.txt\", \"Example3.txt\", \"Example4.txt\", \"Example5.txt\", \"Example6.txt\", \"Example7.txt\", \"Example8.txt\", \"Example9.txt\", \"Example10.txt\",
            \"Example11.txt\", \"Example12.txt\", \"Example13.txt\", \"Example14.txt\", \"Example15.txt\", \"Example16.txt\", \"Example17.txt\", \"Example18.txt\", \"Example19.txt\", \"Example20.txt\"
        };

        items.Sort();

        foreach (var item in items)
        {
            Console.WriteLine(item);
        }

        Console.WriteLine();

        items.Sort(new StrCmpLogicalComparer());

        foreach (var item in items)
        {
            Console.WriteLine(item);
        }
        Console.ReadLine();
    }
}
哪个输出
Example1.txt
Example10.txt
Example11.txt
Example12.txt
Example13.txt
Example14.txt
Example15.txt
Example16.txt
Example17.txt
Example18.txt
Example19.txt
Example2.txt
Example20.txt
Example3.txt
Example4.txt
Example5.txt
Example6.txt
Example7.txt
Example8.txt
Example9.txt

Example1.txt
Example2.txt
Example3.txt
Example4.txt
Example5.txt
Example6.txt
Example7.txt
Example8.txt
Example9.txt
Example10.txt
Example11.txt
Example12.txt
Example13.txt
Example14.txt
Example15.txt
Example16.txt
Example17.txt
Example18.txt
Example19.txt
Example20.txt
    
        尝试这个
sizes.OrderBy(x => Convert.ToInt32(x)).ToList<string>();
注意: 当所有的字符串都可以转换为int时,这将很有帮助。     
        我想如果字符串中包含一些数字,那会更好。 希望它会有所帮助。 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);
    }
}
    
        您说不能将数字转换为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,鲍勃,劳伦,保罗     
        这似乎是一个奇怪的请求,值得一个奇怪的解决方案:
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);
}
    
        该站点讨论字母数字排序,并将以逻辑意义而不是ASCII意义对数字进行排序。它还考虑了周围的alpha: http://www.dotnetperls.com/alphanumeric-sorting 例: C:/TestB/333.jpg 11 C:/TestB/33.jpg 1个 C:/TestA/111.jpg 111楼 C:/TestA/11.jpg 2 C:/TestA/1.jpg 111D 22 111Z C:/TestB/03.jpg 1个 2 11 22 111D 111楼 111Z C:/TestA/1.jpg C:/TestA/11.jpg C:/TestA/111.jpg C:/TestB/03.jpg C:/TestB/33.jpg C:/TestB/333.jpg 代码如下:
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;
    }
}
    
        杰夫·保尔森(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);
    }
}
之所以起作用,是因为唯一检查ѭ19的结果的是结果是否更大,更小或等于零。一个人可以简单地从另一个中减去这些值,而不必处理返回值。 同样,“ 20”方法也不必使用“ 21”块,并且可以从“ 22”中受益。 对于那些不确定的人: 该比较器将对值进行排序,以便始终将非数字值附加到列表的末尾。如果在开始时想要它们,则必须交换第二个和第三个
if
块。     
        尝试这个 :
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);
}
    
        
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 => x,新的NaturalSort())。ToArray(); 我需要它的原因是将其归档在文件名以数字开头的目录中:
public static FileInfo[] GetFiles(string path)
{
  return new DirectoryInfo(path).GetFiles()
                                .OrderBy(x => x.Name, new NaturalSort())
                                .ToArray();
}
    
        
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());               
               }
我试图在这个有趣的问题上做出贡献...     
        我的首选解决方案(如果所有字符串均为数字):
// Order by numerical order: (Assertion: all things are numeric strings only) 
foreach (var thing in things.OrderBy(int.Parse))
{
    Console.Writeline(thing);
}
    
        
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;
    }
}
    
        扩展Jeff Paulsen的答案。我想确保它与字符串中的数字或字符组无关紧要:
public class SemiNumericComparer : IComparer<string>
{
    public int Compare(string s1, string s2)
    {
        if (int.TryParse(s1, out var i1) && int.TryParse(s2, out var i2))
        {
            if (i1 > i2)
            {
                return 1;
            }

            if (i1 < i2)
            {
                return -1;
            }

            if (i1 == i2)
            {
                return 0;
            }
        }

        var text1 = SplitCharsAndNums(s1);
        var text2 = SplitCharsAndNums(s2);

        if (text1.Length > 1 && text2.Length > 1)
        {

            for (var i = 0; i < Math.Max(text1.Length, text2.Length); i++)
            {

                if (text1[i] != null && text2[i] != null)
                {
                    var pos = Compare(text1[i], text2[i]);
                    if (pos != 0)
                    {
                        return pos;
                    }
                }
                else
                {
                    //text1[i] is null there for the string is shorter and comes before a longer string.
                    if (text1[i] == null)
                    {
                        return -1;
                    }
                    if (text2[i] == null)
                    {
                        return 1;
                    }
                }
            }
        }

        return string.Compare(s1, s2, true);
    }

    private string[] SplitCharsAndNums(string text)
    {
        var sb = new StringBuilder();
        for (var i = 0; i < text.Length - 1; i++)
        {
            if ((!char.IsDigit(text[i]) && char.IsDigit(text[i + 1])) ||
                (char.IsDigit(text[i]) && !char.IsDigit(text[i + 1])))
            {
                sb.Append(text[i]);
                sb.Append(\" \");
            }
            else
            {
                sb.Append(text[i]);
            }
        }

        sb.Append(text[text.Length - 1]);

        return sb.ToString().Split(\' \');
    }
}
在修改它以处理文件名之后,我还从SO页中获取了SplitCharsAndNums。     
        即使这是一个古老的问题,我也想给出一个解决方案:
string[] things= new string[] { \"105\", \"101\", \"102\", \"103\", \"90\" };

foreach (var thing in things.OrderBy(x => Int32.Parse(x) )
{
    Console.WriteLine(thing);
}
哇哈很简单吧? :D     
        
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);
            }
        }

    }
}
    

要回复问题请先登录注册