ฉันจะเรียงลำดับสตริงตามตัวอักษรในขณะที่บันทึกค่าเมื่อสตริงเป็นตัวเลขได้อย่างไร


101

ฉันกำลังพยายามจัดเรียงอาร์เรย์ของตัวเลขที่เป็นสตริงและฉันต้องการให้เรียงลำดับตามตัวเลข

สิ่งที่จับได้คือฉันไม่สามารถแปลงตัวเลขเป็น 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" แทน "ขนาด" อาร์เรย์สามารถเป็นดังนี้:

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

นั่นหมายความว่าจะต้องเรียงตามตัวอักษรและตัวเลข:

007, 90, บ๊อบ, ลอเรน, พอล


8
ทำไมคุณถึงแปลงเป็น int ไม่ได้
Femaref

1
"ขนาด" เป็นอย่างอื่นได้เช่น "ชื่อ" ตัวอย่างโค้ดนั้นง่ายขึ้น
sf.

2
ตัวเลขจะเป็นลบหรือไม่? ทั้งหมดจะเป็นจำนวนเต็มหรือไม่? จำนวนเต็มคืออะไร?
Eric Lippert

"things" อาจเป็นสตริงประเภทใดก็ได้ ฉันต้องการจัดเรียงรายการตามเหตุผลสำหรับผู้ที่ไม่มีความรู้ทางคอมพิวเตอร์ จำนวนลบควรอยู่ก่อนบวก ในแง่ของความยาวสตริงจะไม่เกิน 100 ตัวอักษร
sf.

5
คุณต้องการไปไกลแค่ไหน? ควรimage10มาหลังimage2? ควรJanuaryมาก่อนFebruary?
svick

คำตอบ:


104

ส่งตัวเปรียบเทียบแบบกำหนดเองไปยัง 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);
    }
}

1
สำหรับอินพุตที่ระบุสิ่งนี้จะให้ผลลัพธ์เช่นเดียวกับคำตอบของ Recursive ซึ่งเกี่ยวข้องกับ PadLeft () ฉันสมมติว่าข้อมูลที่คุณป้อนมีความซับซ้อนมากกว่าที่ตัวอย่างนี้แสดงซึ่งในกรณีนี้ตัวเปรียบเทียบที่กำหนดเองเป็นวิธีที่จะไป
Jeff Paulsen

ไชโย วิธีนี้ใช้ได้ผลและดูเหมือนเป็นวิธีที่ง่ายต่อการอ่านและทำความสะอาด +1 เพื่อแสดงให้ฉันเห็นว่าคุณสามารถใช้ IComparer บน OrderBy :)
sf

17
IsNumericวิธีการที่ไม่ดีเป็นข้อยกเว้นที่ขับเคลื่อนด้วยการเข้ารหัสอยู่เสมอไม่ดี ใช้int.TryParseแทน ลองใช้รหัสของคุณกับรายการขนาดใหญ่และจะใช้ตลอดไป
Nean Der Thal

หากเป็นประโยชน์ฉันได้เพิ่มส่วนขยายลงในเวอร์ชันนี้ที่นี่ซึ่งเพิ่มการรองรับการเรียงลำดับด้วยคำ สำหรับความต้องการของฉันการแบ่งช่องว่างก็เพียงพอแล้วและฉันไม่จำเป็นต้องกังวลเล็กน้อยเกี่ยวกับคำที่ใช้ผสมกัน (เช่น test12 vs test3)
matt.bungard

@NeanDerThal ฉันค่อนข้างมั่นใจว่ามันเป็นเพียงการจัดการที่ช้า / ไม่ดีข้อยกเว้นมากมายในลูปหากคุณกำลังดีบักหรือคุณกำลังเข้าถึงวัตถุ Exception
Kelly Elton

92

เพียงแค่ใส่ศูนย์ให้มีความยาวเท่ากัน:

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

+1 สำหรับวิธีแก้ปัญหาง่ายๆ nitpicking จะ (แก้ไขเรียบร้อยแล้วดี)
Marino Šimić

ความคิดที่ดี แต่สิ่งที่น่าสนใจต่อไปคือฉันต้องปรับเปลี่ยนค่าเหล่านี้ดังนั้น "90" จึงต้องเป็น "90" ไม่ใช่ "090"
sf

6
@sf: ลองดูสิคุณอาจชอบผลลัพธ์ โปรดจำไว้ว่าคีย์การสั่งซื้อไม่ใช่สิ่งที่สั่งซื้อ ถ้าฉันบอกว่าจะสั่งรายชื่อลูกค้าด้วยนามสกุลฉันก็จะได้รายชื่อลูกค้าไม่ใช่รายชื่อนามสกุล หากคุณบอกว่าจะเรียงลำดับรายการของสตริงด้วยสตริงที่แปลงแล้วผลลัพธ์คือรายการลำดับของสตริงดั้งเดิมไม่ใช่สตริงที่ถูกแปลง
Eric Lippert

ฉันต้องเพิ่ม "sizes = sizes.OrderBy (... )" เพื่อให้ทำงานนี้ เป็นเรื่องปกติหรือควรแก้ไขคำตอบ?
gorgabal

1
@gorgabal: โดยทั่วไปการกำหนดซ้ำให้sizesจะไม่ได้ผลเช่นกันเนื่องจากผลลัพธ์เป็นประเภทอื่น คำตอบเป็นแบบสั้น ๆ โดยบรรทัดที่สองจะแสดงผลลัพธ์เป็นนิพจน์ แต่ขึ้นอยู่กับผู้อ่านว่าจะทำอะไรกับมัน ฉันได้เพิ่มการกำหนดตัวแปรอื่นเพื่อให้ชัดเจนยิ่งขึ้น
ซ้ำ

76

แล้วนี่ ...

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

ฮิฮิฉันชอบอันนี้มาก - ฉลาดมาก ขออภัยหากฉันไม่ได้ให้ข้อมูลเริ่มต้นครบชุด
sf.

3
นี่เป็นเหมือนกับตัวเลือกแผ่นด้านบนเท่านั้น IMO ที่ดีกว่ามาก
dudeNumber4

4
var size = sizes.OrderBy (x => x.Length) .ThenBy (x => x);
Phillip Davis

1
"b", "ab", "101", "103", "bob", "abcd"แต่นี้จะผสมสตริงตัวอักษรเช่นนี้
Andrew

ว้าวคำตอบที่ดี
Peyman Majidi

72

ค่าคือสตริง

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

ผลงาน


3
คำตอบนี้โดนใจ
LacOniC

2
ขอบคุณฉันเพิ่งค้นพบว่าออกจากเมธอด "ThenBy"
ganchito55

ใช้งานได้ดีสำหรับกรณีการใช้งานของฉันโดยที่อินพุตอยู่ในรูปแบบใหม่string[] { "Object 1", "Object 9", "Object 14" }
thelem

3
นี่คือคำตอบที่ดีที่สุด ได้ผลและเป็นการเรียนรู้ที่ดี ขอบคุณ !!
JulyOrdinary

1
"b", "ab", "101", "103", "bob", "abcd"แต่นี้จะผสมสตริงตัวอักษรเช่นนี้
Andrew

14

มีฟังก์ชันดั้งเดิมในหน้าต่าง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

ฉันหวังว่าการใช้ไลบรารีระบบใน C # จะง่ายขึ้น
Kyle Delaney

สิ่งนี้จะสมบูรณ์แบบ แต่น่าเสียดายที่ไม่สามารถจัดการกับจำนวนลบได้ -1 0 10 2จัดเรียงเป็น0 -1 2 10
nphx

5

ลองดู

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

หมายเหตุ: สิ่งนี้จะมีประโยชน์เมื่อสตริงทั้งหมดสามารถแปลงเป็น int .....


1
แบบนี้จะแปลงสตริงเป็น int
Femaref

1
"ขนาด" อาจไม่ใช่ตัวเลข
sf

สำหรับ "LINQ to SQL" อย่าลืมToList()ก่อน =>sizes.ToList().OrderBy(x => Convert.ToInt32(x))
A. Morel

5

ฉันเดาว่านี่จะดีกว่านี้มากถ้ามีตัวเลขอยู่ในสตริง หวังว่ามันจะช่วยได้

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

สิ่งที่ฉันกำลังมองหา ขอบคุณ!
klugerama

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, บ๊อบ, ลอเรน, พอล


Btw ฉันใช้ Array เรียงลำดับเพื่อความเรียบง่าย แต่คุณสามารถใช้ตรรกะเดียวกันใน IComparer และใช้ OrderBy
Ulf Kristiansen

วิธีนี้ดูเหมือนเร็วกว่าเมื่อใช้ IComparer (ความเห็นของฉัน) 15000 ผลลัพธ์และฉันรู้สึกว่าสิ่งนี้ให้ผลต่างประมาณวินาที
Jason Foglia

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

ฉันหมายถึง 0x30 แน่นอน นอกจากนี้อาร์เรย์ยังคงมีสตริงที่ไม่ใช่ตัวเลขซึ่งโซลูชันจะให้ผลลัพธ์ที่น่าสนใจ
Femaref

และสังเกตว่า -48 หรือไม่เปลี่ยนแปลงอะไรเลยเราสามารถใช้ค่าจำนวนเต็มของถ่านได้โดยตรงดังนั้นให้ลบ -48 นั้นออกถ้ามันรบกวนคุณ ...
Marino Šimić

ค่าถ่านคือ 0x30 หากคุณแปลงเป็น int ก็จะยังคงเป็น 0x30 ซึ่งไม่ใช่ตัวเลข 0
Femaref

สิ่งเดียวที่แปลงเป็นจำนวนเต็มคือผลคูณที่ส่งคืนจาก Math.Pow
Marino Šimić

femaref มันไม่สำคัญว่ามันจะเป็นศูนย์หรือไม่ระบบเสื่อมจะดูแลมันอาจเป็นĐถ้าคุณต้องการสิ่งเดียวที่สำคัญคือตัวเลขอยู่ในลำดับจากน้อยไปหามากในชุดอักขระและนั่นน้อยกว่า 10
Marino Šimić

3

ไซต์นี้กล่าวถึงการเรียงลำดับตัวอักษรและตัวเลขและจะเรียงลำดับตัวเลขในเชิงตรรกะแทนความรู้สึก ASCII นอกจากนี้ยังคำนึงถึงอัลฟ่าที่อยู่รอบ ๆ :

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

ตัวอย่าง:

  • C: /TestB/333.jpg
  • 11
  • C: /TestB/33.jpg
  • 1
  • C: /TestA/111.jpg
  • 111F
  • C: /TestA/11.jpg
  • 2
  • C: /TestA/1.jpg
  • 111 ด
  • 22
  • 111Z
  • C: /TestB/03.jpg

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

รหัสมีดังนี้:

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

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วิธีนี้ไม่ควรต้องใช้ a try-block และจะได้รับประโยชน์จากTryParseและได้รับประโยชน์จาก

และสำหรับผู้ที่ไม่แน่ใจ: Comparer นี้จะเรียงลำดับค่าดังนั้นค่าที่ไม่ใช่ตัวเลขจะถูกต่อท้ายรายการเสมอ หากต้องการตั้งแต่เริ่มต้นifบล็อกที่สองและสามจะต้องสลับกัน


เนื่องจากการเรียกเมธอด TryParse อาจมีค่าใช้จ่ายบางส่วนฉันจะเก็บค่า isNumeric สำหรับ s1 และ s2 เป็นค่าบูลีนก่อนและทำการเปรียบเทียบกับค่าเหล่านั้นแทน วิธีนี้จะไม่ได้รับการประเมินหลายครั้ง
Optavius

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

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, NaturalSort ใหม่ ()) ToArray ();

เหตุผลที่ฉันต้องการคือการยื่นในไดเรกทอรีที่มีชื่อไฟล์ขึ้นต้นด้วยตัวเลข:

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

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

ฉันพยายามที่จะมีส่วนร่วมในคำถามที่น่าสนใจนี้ ...


0

วิธีแก้ปัญหาที่ฉันต้องการ (หากสตริงทั้งหมดเป็นตัวเลขเท่านั้น):

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

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

คุณสามารถอธิบายรหัสของคุณได้หรือไม่? คำตอบที่ใช้รหัสเท่านั้นอาจถูกลบ
Wai Ha Lee

โพสต์ของ Jeff Paulsen ช่วยฉันในการติดตั้ง IComparer <string> เพื่อแก้ไขปัญหาการป่วยของฉัน .
kumar

0

ขยายคำตอบของ 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(' ');
    }
}

ฉันยังเอา SplitCharsAndNums จากSO Pageหลังจากแก้ไขเพื่อจัดการกับชื่อไฟล์


-1

แม้ว่านี่จะเป็นคำถามเก่า แต่ฉันก็อยากจะให้คำตอบ:

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

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

ว้าวค่อนข้างง่ายใช่มั้ย? : ง


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

    }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.