51

値の順序を知らなくても、一連の値 (この場合は文字列) に対して OrderBy を実行する方法は Linq にありますか?

次のデータを検討してください。

A
B
A
C
B
C
D
E

そして、これらの変数:

文字列 firstPref、secondPref、thirdPref;

値が次のように設定されている場合:

firstPref = 'A';
secondPref = 'B';
thirdPref = 'C';

次のようにデータを注文することは可能ですか。

A
A
B
B
C
C
D
E
4

8 に答える 8

131

好みをリストに入れておけば、もっと簡単になるかもしれません。

List<String> data = new List<String> { "A","B","A","C","B","C","D","E" };
List<String> preferences = new List<String> { "A","B","C" };

IEnumerable<String> orderedData = data.OrderBy(
   item => preferences.IndexOf(item));

これにより、が返されるため、表示されていないすべての項目がpreferences前面に表示されます。その場しのぎの回避策として、結果を逆にして降順で並べることができます。これはかなり醜くなりますが、機能します。IndexOf()-1preferences

IEnumerable<String> orderedData = data.OrderByDescending(
   item => Enumerable.Reverse(preferences).ToList().IndexOf(item));

preferencesと を連結すると、ソリューションは少し良くなりますdata

IEnumerable<String> orderedData = data.OrderBy(
   item => preferences.Concat(data).ToList().IndexOf(item));

Concat()私は好きではありませんToList()。しかし、今のところ、それを回避する良い方法はありません。-1最初の例の を大きな数に変える素敵なトリックを探しています。

于 2009-04-08T02:55:30.847 に答える
7

優先値を辞書に入れます。ディクショナリ内のキーの検索は、O(n) 操作であるリスト内の値の検索と比較して O(1) 操作であるため、スケーリングがはるかに優れています。

優先値ごとにソート文字列を作成して、優先値が他の値の前に配置されるようにします。他の値については、値自体がソート文字列として使用されるため、実際にソートされます。(任意の高い値を使用すると、ソートされていないリストの最後にのみ配置されます)。

List<string> data = new List<string> {
    "E", "B", "D", "A", "C", "B", "A", "C"
};
var preferences = new Dictionary<string, string> {
    { "A", " 01" },
    { "B", " 02" },
    { "C", " 03" }
};

string key;
IEnumerable<String> orderedData = data.OrderBy(
    item => preferences.TryGetValue(item, out key) ? key : item
);
于 2009-04-08T07:42:47.253 に答える
2

Danbrucs ソリューションはより洗練されていますが、カスタム IComparer を使用したソリューションを次に示します。これは、ソート順により高度な条件が必要な場合に役立ちます。

    string[] svals = new string[] {"A", "B", "A", "C", "B", "C", "D", "E"};
    List<string> list = svals.OrderBy(a => a, new CustomComparer()).ToList();

    private class CustomComparer : IComparer<string>
    {
        private string firstPref = "A";
        private string secondPref = "B";
        private string thirdPref = "C";
        public int Compare(string x, string y)
        {
            // first pref 
            if (y == firstPref && x == firstPref)
                return 0;
            else if (x == firstPref && y != firstPref)
                return -1;
            else if (y == firstPref && x != firstPref)
                return 1;
            // second pref
            else if (y == secondPref && x == secondPref)
                return 0;
            else if (x == secondPref && y != secondPref)
                return -1;
            else if (y == secondPref && x != secondPref)
                return 1;
            // third pref
            else if (y == thirdPref && x == thirdPref)
                return 0;
            else if (x == thirdPref && y != thirdPref)
                return -1;
            else
                return string.Compare(x, y);
        }
    }
于 2009-04-08T03:22:37.723 に答える
1

はい、独自のものを実装し、IComparer<string>それを LINQ の OrderBy メソッドの 2 番目の引数として渡す必要があります。

例はここにあります: LINQ 結果の順序付け

于 2009-04-08T02:50:36.053 に答える