116

文字列である数値の配列をソートしようとしていますが、数値でソートしたいと思います。

問題は、数値を 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, bob, lauren, paul
4

21 に答える 21

115

カスタム比較子を OrderBy に渡します。Enumerable.OrderByを使用すると、好きな比較子を指定できます。

これを行う 1 つの方法は次のとおりです。

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);
    }
}
于 2011-06-18T16:18:04.143 に答える
110

同じ長さにゼロをパディングするだけです:

int maxlen = sizes.Max(x => x.Length);
var result = sizes.OrderBy(x => x.PadLeft(maxlen, '0'));
于 2011-06-18T13:56:31.860 に答える
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);
}
于 2011-06-18T14:33:51.917 に答える
5

配列には 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、ボブ、ローレン、ポール

于 2014-05-15T17:34:37.487 に答える
5

try this

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

Note: this will helpful when all are string convertable to int.....

于 2011-06-18T13:38:47.980 に答える
4

このサイトでは、英数字の並べ替えについて説明し、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
  • 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

コードは次のとおりです。

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;
    }
}
于 2014-09-29T22:40:53.867 に答える
3

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メソッドはtry-block を使用する必要はなく、 の恩恵を受けることができTryParseます。

よくわからない人のために: この Comparer は値を並べ替えて、数値以外の値が常にリストの最後に追加されるようにします。最初にそれらが必要な場合は、2 番目と 3 番目のifブロックを交換する必要があります。

于 2014-11-26T20:58:27.467 に答える
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);
}
于 2011-06-18T13:45:50.167 に答える
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());               
               }

私はこの興味深い質問に貢献しようとしました...

于 2011-06-18T18:43:24.173 に答える
-1

これは古い質問ですが、解決策を提供したいと思います。

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

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

とてもシンプルですね。:D

于 2014-06-19T14:53:51.020 に答える