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

问题描述 投票:89回答:19

我正在尝试对一组数字进行排序,这些数字是字符串,我希望它们以数字方式进行排序。

问题是我无法将数字转换为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 ...

更新了代码示例,使其说的是“东西”,而不是“大小”。数组可以是这样的:

string[] things= new string[] { "paul", "bob", "lauren", "007", "90" };

这意味着它需要按字母顺序和数字排序:

007、90,鲍勃,劳伦,保罗

c# linq sorting alphabetical alphanumeric
19个回答
96
投票

将自定义比较器传递到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);
    }
}

2
投票

此站点讨论了字母数字排序,并将以逻辑方式而不是ASCII方式对数字进行排序。它还考虑了周围的Alpha:


2
投票

杰夫·保尔森(Jeff Paulsen)给出的答案是正确的,但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; } } 可以简化为:


1
投票

尝试一下:


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);
}

0
投票
public static FileInfo[] GetFiles(string path)
{
  return new DirectoryInfo(path).GetFiles()
                                .OrderBy(x => x.Name, new NaturalSort())
                                .ToArray();
}

0
投票

我的首选解决方案(如果所有字符串均为数字):


0
投票
// Order by numerical order: (Assertion: all things are numeric strings only) 
foreach (var thing in things.OrderBy(int.Parse))
{
    Console.Writeline(thing);
}

0
投票

扩展Jeff Paulsen的答案。我想确保字符串中有多少个数字或字符组都没关系:


-1
投票

即使这是一个老问题,我也想提供一个解决方案:


-1
投票
string[] things= new string[] { "105", "101", "102", "103", "90" };

foreach (var thing in things.OrderBy(x => Int32.Parse(x) )
{
    Console.WriteLine(thing);
}

85
投票

只需将零填充到相同的长度:

int maxlen = sizes.Max(x => x.Length);
sizes.OrderBy(x => x.PadLeft(maxlen, '0'));

68
投票

而且,这呢...

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);
}

56
投票

值是一个字符串

List = List.OrderBy(c => c.Value.Length).ThenBy(c => c.Value).ToList();

Works


7
投票

[windows StrCmpLogicalW中有一个本机函数,它将以数字而不是字母的形式比较字符串中的数字。创建一个比较器可以很容易地调用该函数并将其用于比较。

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); } } 排序之间的差异

StrCmpLogicalW

输出

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();
    }
}

5
投票

尝试一下

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

注意:当所有的字符串都可以转换为int时,这将很有帮助。


4
投票

您说您不能将数字转换为int,因为数组可以包含无法转换为int的元素,但是尝试这样做没有害处:


4
投票

我想如果字符串中包含数字,那会更好。希望对您有所帮助。


3
投票

这似乎是一个奇怪的请求,应该得到一个奇怪的解决方案:

© www.soinside.com 2019 - 2024. All rights reserved.