2017-02-28 3 views
1

私はは、他の人の後に特定の要素を移動ではなく、上部にまたは下部

{ "w", "w", "z", "a", "c", "r", "f", "d", "e", "c", "g", "f", "m", "z" } 

の配列を持っていると私はすべての「c」は「F」の前に移動させなければならないルールがあるとします。 ルールに従っている最中にできるだけオリジナルに近い順序を保つことの目標。 現実世界の例は、一部のプラグイン "A"がロードリストの一部のプラグイン "B"よりも高いはずであることを知っているアプリです。

だから、期待される結果は次のようになります。最初のFの前に

移動C:

{ "w", "w", "z", "a", "c", "r", "c"<<, "f", "d", "e", "g", "f", "m", "z" } 

または

最後のCの後にfを移動:

{ "w", "w", "z", "a", "c", "r", "d", "e", "c", >>"f", "g", "f", "m", "z" } 

がすることが可能ですこのような目的のために準備されたLINQまたは何かを使用しますか?

私はOrderBy(x => x == "c" ? 0 : x == "f" ? 1 : (int?)null)を試しましたが、代わりに要素を最後まで移動します。私は、特定の要素だけを互いに並べ替えたいが、可能であれば他の要素との相対的な位置を保持したい。

UPDATE

溶液は、任意の入力のために働くべきである:

public static char GetLetter(Random rand) 
    { 
     string chars = "abcdefghijklmnopqrstuvwxyz"; 
     int num = rand.Next(0, chars.Length - 1); 
     return chars[num]; 
    } 

    public static IEnumerable<string> Sort(IEnumerable<string> enumerable, string first, string second) 
    { 
     ??? 

    } 

    static void Main(string[] args) 
    { 
     Random rand = new Random(); 
     string[] input = Enumerable.Range(1, 10).Select(x => GetLetter(rand) + "").ToArray(); 
     var result = Sort(Sort(input, "c", "f"), "m", "e"); 
    } 

を複数の要素( "M"、 "C"、 "F")と複数のルールをサポートすることがdoesnの場合に望ましいです物事が複雑すぎる。

+0

代わりに 'List 'を使用することはできますか?これにより、指定したインデックスに挿入/削除することが可能になります。これは、配列で行うことはできますが、1行のLINQよりも困難です。 – Equalsk

+0

これはメモリ内に発生しているのですか、またはLINQがSQLに変換されていますか? –

+0

メモリ内の@RobLang – Vlad

答えて

2

この方法は、あなたが欲しいものを行います。

public static IEnumerable<string> Sort(this IEnumerable<string> enumerable, string first, string second) 
{ 
    return enumerable.TakeWhile(s => s != second) 
     .Concat(enumerable.SkipWhile(s => s != second).OrderBy(a => a != first)); 
} 

アイデアは、最初のリストの一部は、(この場合)最初fまで取られていることです。残りの部分が追加され、最初にc文字でソートされます。

欠点は、リストが2回(一部)列挙されることです。これがパフォーマンス上重要な場合は、1回だけ列挙する代替手段を選択する必要があります。

1

これがソリューションです:

string[] ch = {"a", "c", "f", "d", "e", "c", "g", "f", "m"}; 
var res = ch.Select((item, index) => new { item, index }) 
      .OrderBy(x => x.item == "c" ? 0 : Convert.ToInt32(x.index)) 
      .Select(c => c.item).ToArray(); 

出力:

enter image description here

+0

あなたのソリューションはこれに適しています"f"をどのように指定しますか?後で "c"と "g"を並べ替える場合はどうしますか?ここでは「c」とだけ並べ替えます。 – Vlad

+0

@Vladそれはあなたのルールに基づいて動作します:*と私はすべての "c"は "f"の前に移動する必要があるというルールを持っています。*したがって、それは 'f'または' g'または..... 'c'文字を最初にソートし、' f'や 'g'や...に関係なく、あなたが質問で示した最初の期待結果を常に生成します。 –

+0

特定の入力に固執します。ルールは* all "c"は "f" *の前に移動されなければならず、この "a"、 "c"、 "f"、 "d"だけでなく要素の配列にも適用できる必要があります。 、 "e"、 "c"、 "g"、 "f"、 "m" * – Vlad

0

では正しくあなたの質問を理解している場合、私はあなたがルールを定義しますする配列規則を持っている必要があると思いますどのキャラクターが最初に来るかのように。ここで私はあなたの先輩を考慮してテストを追加しています。ルールを変更して使用することができます。

[Test] 
    public void CustomOrderByTests() 
    { 
     char[] ch = { 'a', 'c', 'f', 'd', 'e', 'c', 'g', 'f', 'm' }; 
     char[] rules = { 'a', 'f', 'c' }; 

     var result = rules.Intersect(ch).Union(ch); 

     char[] expected = { 'a', 'f', 'c', 'd', 'e', 'g', 'm' }; 
     CollectionAssert.AreEqual(result, expected); 
    } 

あなたが使用する前にArray.Sort()過負荷を同じ位置に重複した要素をしたい場合は、それが短い結果、重複

Array.Sort(rules, ch); 

を取り外すことなく、今あなたのch配列がソートされた配列を持つことになります。

+0

1.出力には期待されない別の要素数が含まれています。これは、シーケンスの最初にすべて移動します。しかし、最初にポジションを維持すべき要素が他にもあるかもしれません。 x、r、z、a、c、f、d、e、c、g、f、 m '*私はその質問を編集した。 – Vlad

+0

1.何の要素数ですか?あなたが別の要素を持っていれば、正しい位置にルール配列を追加します。 –

+0

9つの要素があり、出力は7つの要素です。 – Vlad