[c#] 문자열이 숫자 일 때 값을 고려하면서 문자열을 알파벳순으로 정렬하는 방법은 무엇입니까?

문자열 인 숫자 배열을 정렬하려고하는데 숫자로 정렬하고 싶습니다.

문제 는 숫자를 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, 밥, 로렌, 폴



답변

사용자 지정 비교자를 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);
    }
}


답변

같은 길이로 0으로 채 웁니다.

int maxlen = sizes.Max(x => x.Length);
var result = 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);
    }
}

텍스트와 숫자가 모두있는 문자열에서도 작동합니다. 여기에 기본 정렬과 사이의 디퍼 런스 세라마이드 표시하는 예제 프로그램입니다 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();
    }
}

어느 출력

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 …..로 변환 가능한 경우에 유용합니다.


답변

문자열에 숫자가 있으면 훨씬 더 좋을 것 같습니다. 도움이되기를 바랍니다.

추신 : 성능이나 복잡한 문자열 값에 대해서는 잘 모르겠지만 다음과 같이 잘 작동했습니다.

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