Jak sortować ciągi alfabetycznie, biorąc pod uwagę wartość, gdy ciąg jest liczbowy?

100

Próbuję posortować tablicę liczb, które są ciągami znaków i chciałbym, aby posortowano je numerycznie.

Problem polega na tym , że nie mogę zamienić liczb na int .

Oto kod:

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

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

wyjście: 101, 102, 103, 105, 90

Chciałbym: 90, 101, 102, 103, 105

EDYCJA: Wyjście nie może być 090, 101, 102 ...

Zaktualizowano przykładowy kod, aby mówił „rzeczy” zamiast „rozmiary”. Tablica może wyglądać mniej więcej tak:

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

Oznacza to, że należy posortować alfabetycznie i według numerów:

007, 90, Bob, Lauren, Paul

sf.
źródło
8
Dlaczego nie możesz przekonwertować ich na int?
Femaref
1
„rozmiary” mogą oznaczać coś innego, np. „nazwa”. Przykładowy kod jest po prostu uproszczony.
sf.
2
Czy któraś z liczb będzie ujemna? Czy wszystkie będą liczbami całkowitymi? Jaki jest zakres liczb całkowitych?
Eric Lippert
„rzeczy” mogą być dowolnym ciągiem. Chciałbym, aby lista była logicznie posortowana dla osoby nie znającej się na komputerze. Liczby ujemne powinny znajdować się przed dodaniem. Jeśli chodzi o długość łańcucha, nie będzie to więcej niż 100 znaków.
sf.
5
Jak daleko chcesz się posunąć? Powinien image10przyjść później image2? Powinien Januaryprzyjść wcześniej February?
svick

Odpowiedzi:

104

Przekaż niestandardową funkcję porównującą do OrderBy. Enumerable.OrderBy pozwoli ci określić dowolną porównywalną.

Oto jeden ze sposobów, aby to zrobić:

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);
    }
}
Jeff Paulsen
źródło
1
Dla podanych danych wejściowych daje to ten sam wynik, co odpowiedź Recursive, która obejmuje PadLeft (). Zakładam, że twoje dane wejściowe są w rzeczywistości bardziej złożone niż pokazuje ten przykład, w takim przypadku niestandardowa funkcja porównująca jest najlepszym rozwiązaniem.
Jeff Paulsen
Twoje zdrowie. To rozwiązanie działa i wydaje się być łatwym do odczytania i czystym sposobem wdrożenia. +1 za pokazanie mi, że możesz używać IComparer na OrderBy :)
sf.
17
IsNumericMetoda jest zła, wyjątek napędzany kodowanie jest zawsze złe. Użyj int.TryParsezamiast tego. Wypróbuj swój kod z dużą listą, a zajmie to wieczność.
Nean Der Thal
Jeśli jest to pomocne, dodałem tutaj rozszerzenie do tej wersji , które dodaje obsługę sortowania według słów. Dla moich potrzeb podział na spacje był wystarczający i nie musiałem martwić się o słowa mieszane (np. Test12 vs test3),
matt.bungard
@NeanDerThal Jestem prawie pewien, że tylko wolno / źle obsługuje wiele wyjątków w pętli, jeśli debugujesz lub uzyskujesz dostęp do obiektu Exception.
Kelly Elton
90

Po prostu uzupełnij zerami do tej samej długości:

int maxlen = sizes.Max(x => x.Length);
var result = sizes.OrderBy(x => x.PadLeft(maxlen, '0'));
rekurencyjny
źródło
+1 za proste rozwiązanie, dziurawienie dziury (już zrobione w edycji, fajnie)
Marino Šimić
Niezły pomysł, ale następny haczyk polega na tym, że muszę wyświetlić te wartości, więc „90” musi być „90”, a nie „090”
sf.
6
@sf: Spróbuj, może Ci się spodobać wynik. Pamiętaj, że klucz zamówienia nie jest przedmiotem zamówienia. Gdybym powiedział, żebym uporządkował listę klientów według nazwiska, otrzymuję listę klientów, a nie listę nazwisk. Jeśli powiesz, że chcesz uporządkować listę ciągów według przekształconego ciągu, wynikiem jest uporządkowana lista oryginalnych ciągów, a nie przekształconych.
Eric Lippert
Musiałem dodać „rozmiary = rozmiary.OrderBy (...)”, aby to działało. Czy to normalne, czy też należy zredagować odpowiedź?
gorgabal
1
@gorgabal: Generalnie ponowne przypisanie do sizesrównież nie zadziała, ponieważ wynik jest innego typu. Odpowiedź jest trochę krótka, ponieważ druga linia pokazuje wynik jako wyrażenie, ale czytelnik musi coś z tym zrobić. Dodałem kolejne przypisanie zmiennej, aby było to bardziej zrozumiałe.
rekurencyjne
74

A co powiesz na to ...

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);
}
shenhengbin
źródło
hehe, bardzo mi się to podoba - bardzo sprytne. Przepraszam, jeśli nie podałem pełnego zestawu danych początkowych
sf.
3
To jest tak samo jak opcja podkładki powyżej, tylko znacznie lepsza IMO.
dudeNumber4
3
var size =izes.OrderBy (x => x.Length) .ThenBy (x => x);
Phillip Davis
1
Ale to będzie mieszać alfabetycznych sznurki jak to: "b", "ab", "101", "103", "bob", "abcd".
Andrew
67

Wartość to ciąg

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

Pracuje

Echo
źródło
2
Ta odpowiedź jest moją ulubioną.
LacOniC,
2
Dzięki. Właśnie odkryłem, że wychodzi z metody „ThenBy”.
ganchito55
Działa to świetnie w moim przypadku użycia, gdzie dane wejściowe są w formacie nowystring[] { "Object 1", "Object 9", "Object 14" }
thelem
2
To najlepsza odpowiedź. Działa i dobrze się uczy. Dzięki !!
Zwykły
1
Ale to będzie mieszać alfabetycznych sznurki jak to: "b", "ab", "101", "103", "bob", "abcd".
Andrew
13

W oknach istnieje natywna funkcja StrCmpLogicalW, która porównuje w łańcuchach liczby jako liczby zamiast liter. Łatwo jest utworzyć moduł porównujący, który wywołuje tę funkcję i używa jej do porównań.

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

Działa nawet na łańcuchach zawierających zarówno tekst, jak i liczby. Oto przykładowy program, który pokaże różnicę między domyślnym sortowaniem a StrCmpLogicalWsortowaniem

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

które wyjścia

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
Scott Chamberlain
źródło
Żałuję, że nie było łatwiej używać bibliotek systemowych w C #
Kyle Delaney
Byłoby to idealne, ale niestety nie obsługuje liczb ujemnych. -1 0 10 2jest sortowany jako0 -1 2 10
nphx
5

Spróbuj tego

sizes.OrderBy(x => Convert.ToInt32(x)).ToList<string>();

Uwaga: będzie to pomocne, gdy wszystkie można zamienić na ciągi znaków typu int .....

Pranay Rana
źródło
1
ten rodzaj konwertuje ciąg na int.
Femaref
1
„rozmiary” mogą być również nienumeryczne
sf.
W przypadku „LINQ to SQL” nie zapomnij o ToList()przed =>sizes.ToList().OrderBy(x => Convert.ToInt32(x))
A. Morel
5

Wydaje mi się, że będzie to znacznie lepsze, jeśli będzie zawierał jakiś numer w ciągu. Mam nadzieję, że to pomoże.

PS: Nie jestem pewien wydajności lub skomplikowanych wartości ciągów, ale działało dobrze, coś takiego:

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);
    }
}
Cansın Şenalioğlu
źródło
Dokładnie to, czego szukałem. Dziękuję Ci!
klugerama
4

Mówisz, że nie możesz zamienić liczb na int, ponieważ tablica może zawierać elementy, których nie można przekonwertować na int, ale nie ma nic złego w próbowaniu:

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

Następnie porównaj w ten sposób:

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

Wyjście: 007, 90, 90, 101, 102, 103, 105, bob, lauren, paul

Ulf Kristiansen
źródło
Przy okazji, użyłem Array.Sort dla uproszczenia, ale możesz użyć tej samej logiki w IComparer i użyć OrderBy.
Ulf Kristiansen
To rozwiązanie wydaje się szybsze niż przy użyciu IComparer (moja opinia). Wynik 15000 i czuję, że daje to około drugiej różnicy.
Jason Foglia
3

Wydaje się to dziwna prośba i zasługuje na dziwne rozwiązanie:

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);
}
Marino Šimić
źródło
Miałem na myśli oczywiście 0x30. Ponadto tablica nadal może zawierać nieliczbowy ciąg znaków, dla którego rozwiązanie da interesujące wyniki.
Femaref
I zauważ, że -48 lub nie zmienia absolutnie nic, możemy bezpośrednio użyć wartości całkowitej znaku, więc usuń to -48, jeśli ci to przeszkadza ...
Marino Šimić
Wartość char to 0x30, jeśli przekonwertujesz to na int, nadal będzie to 0x30, co nie jest liczbą 0.
Femaref
Jedyną rzeczą przekształca się całkowita jest podwójne, który jest zwrócony od Math.pow
Marino Šimić
femaref nie ma znaczenia, czy jest zero, czy nie, zadba o to system dekadowy, może to być Đ, jeśli chcesz, jedyną rzeczą, która ma znaczenie, jest to, że liczby są w porządku rosnącym w zestawie znaków i że są mniejsze niż 10
Marino Šimić
3

Ta witryna omawia sortowanie alfanumeryczne i posortuje liczby w sensie logicznym zamiast ASCII. Bierze również pod uwagę alfy wokół niego:

http://www.dotnetperls.com/alphanumeric-sorting

PRZYKŁAD:

  • 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

  • 1
  • 2
  • 11
  • 22
  • 111D
  • 111F
  • 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

Kod wygląda następująco:

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;
    }
}
Chad Kuehn
źródło
2

Odpowiedź udzielona przez Jeffa Paulsena jest poprawna, ale Comprarermożna ją znacznie uprościć:

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

To działa, ponieważ jedyną rzeczą, która jest sprawdzana pod kątem wyniku, Comparerjest to, czy wynik jest większy, mniejszy lub równy zero. Można po prostu odjąć wartości od innych i nie trzeba zajmować się wartościami zwracanymi.

Również IsNumericmetoda nie powinna używać opcji try-block i może przynieść korzyści TryParse.

A dla tych, którzy nie są pewni: ten Porównywacz posortuje wartości w taki sposób, aby wartości nienumeryczne były zawsze dołączane na końcu listy. Jeśli ktoś chce je na początku, ifnależy zamienić drugi i trzeci blok.

nakrętka k
źródło
Ponieważ wywołanie metody TryParse prawdopodobnie wiąże się z pewnym narzutem, najpierw zapisałbym wartości isNumeric dla s1 i s2 w wartościach logicznych i zamiast tego wykonałbym porównanie. W ten sposób nie są oceniane wielokrotnie.
Optavius
1

Spróbuj tego :

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);
}
TMAmine
źródło
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 => x, new NaturalSort ()). ToArray ();

Powodem, dla którego potrzebowałem, było umieszczenie go w katalogu, którego nazwy plików zaczynały się od numeru:

public static FileInfo[] GetFiles(string path)
{
  return new DirectoryInfo(path).GetFiles()
                                .OrderBy(x => x.Name, new NaturalSort())
                                .ToArray();
}
Neil M.
źródło
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]);
            }


        }

Teraz posortuj listy i połącz je z powrotem ...

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

Próbowałem tylko wnieść swój wkład w to interesujące pytanie ...

Syeda
źródło
0

Moje preferowane rozwiązanie (jeśli wszystkie ciągi są tylko numeryczne):

// Order by numerical order: (Assertion: all things are numeric strings only) 
foreach (var thing in things.OrderBy(int.Parse))
{
    Console.Writeline(thing);
}
Bug Raptor
źródło
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;
    }
}
kumar
źródło
Czy możesz wyjaśnić swój kod? Odpowiedzi zawierające tylko kod mogą zostać usunięte.
Wai Ha Lee
Post Jeffa Paulsena pomógł mi zaimplementować IComparer <string>, aby naprawić mój problem z soringiem. .
kumar
0

Poszerzenie odpowiedzi Jeffa Paulsena. Chciałem się upewnić, że nie ma znaczenia, ile liczb lub grup znaków znajduje się w łańcuchach:

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

Wziąłem również SplitCharsAndNums z SO Page po poprawieniu go, aby poradzić sobie z nazwami plików.

Tod
źródło
-1

Mimo że jest to stare pytanie, chciałbym podać rozwiązanie:

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

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

Woha całkiem proste, prawda? :RE

Oscar Ortiz
źródło
-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);
            }
        }

    }
}
hamid ramezanali
źródło