2017-03-10 3 views
1

Ich habe 2 Listen verschiedener Typen. Ich denke für jetzt ist es egal welche Typen das sind. Beide Typen haben eine Information über Vorkommen, die in Ticks ist (aber auch eine DateTime sein kann).C# synchronisieren 2 Listen verschiedener Typen nach Zeit

Was ich tun möchte, ist, diese 2 Listen nach der Zeit zu synchronisieren, damit ich zum Beispiel alle Elemente in der Reihenfolge durchlaufen kann, wie sie in der Zeit vorkamen.

Example: // in this example List has elements called A_NUM or B_NUM depending on a type of list and number after '_' will represent order at which this elements/events occured 
ListA = {A_2, A_3, A_5} 
ListB = {B_1, B_4, B_6} 

Und das Ergebnis nach der Synchronisierung so etwas wie dies sein wird:

ResultList = {B_1, A_2, A_3, B_4, A_5, B_6} 

Ist es irgendwie möglich, eine solche gemischte Liste zu machen? Oder ich muss eine Hilfsliste oder ein Wörterbuch erstellen, das mir die synchronisierte Reihenfolge dieser 2 Listen anzeigt?

EDIT:

Eine Liste ist eine Liste von Augenfixierungen. Fixierung hat eine Position, Dauer, ... und auch Vorkommensattribute. Zweite Liste ist eine Liste einiger Textänderungen, zum Beispiel in Zeile 12 Spalte 3 wurde ein char 'x' irgendwann hinzugefügt t.

Und ich möchte diese 2 Listen gleichzeitig durchlaufen. Ich meine zur Zeit t1 Fixierung trat bei Position x,y. Zur Zeit t2 gab es eine Textänderung an der Position u,v, also möchte ich diese Ereignisse in der Reihenfolge durchlaufen, wie sie in der Zeit auftraten.

Hinweis: JA Beide Listen sind nach Zeit sortiert. Es ist eine Sequenz von Fixierungen und Folge von Textänderungen.

+0

Was hast du schon probiert? – maccettura

+0

Die Arten der Listen Matter, was ist der Typ der 'ResultList'? –

+0

Verwenden Sie 'concat()' für diese –

Antwort

3

Ihre Frage empfiehlt dringend, eine Zusammenführungssortierung als grundlegendes Implementierungsdetail zu verwenden. Sie haben zwei Eingaben, die beide sortiert sind und nur zusammengeführt werden sollen.

Die Hauptschwierigkeit Ihrer Frage besteht darin, dass Sie versuchen, Sequenzen zweier völlig unverwandter Typen zusammenzuführen. Normalerweise würden Sie Sequenzen desselben Typs zusammenführen und sie so leicht zusammen bearbeiten. Abgesehen davon würden sie zumindest eine Basisklasse oder einen Schnittstellentyp teilen, so dass Sie sie als einen einzigen verallgemeinerten Typ behandeln könnten. Aber es scheint, aus Ihrer Frage, dass dies nicht der Fall ist.

Vor diesem Hintergrund denke ich, der einfachste Weg ist immer noch eine Zusammenführung Sortierung zu verwenden, aber einen Mechanismus für die Sortierung auf die entsprechende Eigenschaft (Ticks, DateTime, was auch immer). Die Sortierung würde die zusammengeführten Sequenzen in der richtigen Reihenfolge als Typ object zurückgeben (d. H. Der einzige Basistyp, der beiden Eingängen gemeinsam ist), und der Aufrufer müsste dann für jeden Zweck zu den einzelnen Typen zurückkehren.

Hier ist ein Beispiel dafür, was ich meine:

private static IEnumerable<TBase> Merge<TBase, T1, T2, TValue>(
     IEnumerable<T1> sequence1, IEnumerable<T2> sequence2, 
     Func<T1, TValue> valueSelector1, Func<T2, TValue> valueSelector2) 
    where T1 : TBase 
    where T2 : TBase 
    where TValue : IComparable<TValue> 
{ 
    IEnumerator<T1> enumerator1 = sequence1.GetEnumerator(); 
    IEnumerator<T2> enumerator2 = sequence2.GetEnumerator(); 
    bool notDone1 = enumerator1.MoveNext(), 
     notDone2 = enumerator2.MoveNext(); 

    while (notDone1 && notDone2) 
    { 
     TValue value1 = valueSelector1(enumerator1.Current), 
      value2 = valueSelector2(enumerator2.Current); 

     if (value1.CompareTo(value2) <= 0) 
     { 
      yield return enumerator1.Current; 
      notDone1 = enumerator1.MoveNext(); 
     } 
     else 
     { 
      yield return enumerator2.Current; 
      notDone2 = enumerator2.MoveNext(); 
     } 
    } 

    while (notDone1) 
    { 
     yield return enumerator1.Current; 
     notDone1 = enumerator1.MoveNext(); 
    } 

    while (notDone2) 
    { 
     yield return enumerator2.Current; 
     notDone2 = enumerator2.MoveNext(); 
    } 
} 

wie folgt verwendet:

class A 
{ 
    public int Value { get; } 

    public A(int value) 
    { 
     Value = value; 
    } 
} 

class B 
{ 
    public int Value { get; } 

    public B(int value) 
    { 
     Value = value; 
    } 
} 

static void Main(string[] args) 
{ 
    const int minCount = 5, maxCount = 15, maxValue = 50; 
    Random random = new Random(); 
    int listACount = random.Next(minCount, maxCount), 
     listBCount = random.Next(minCount, maxCount); 
    A[] listA = RandomOrderedSequence(random, maxValue, listACount).Select(i => new A(i)).ToArray(); 
    B[] listB = RandomOrderedSequence(random, maxValue, listBCount).Select(i => new B(i)).ToArray(); 

    Console.WriteLine("listA: "); 
    Console.WriteLine(string.Join(", ", listA.Select(a => a.Value))); 
    Console.WriteLine("listB: "); 
    Console.WriteLine(string.Join(", ", listB.Select(b => b.Value))); 

    foreach (object o in Merge<object, A, B, int>(listA, listB, a => a.Value, b => b.Value)) 
    { 
     A a = o as A; 

     if (a != null) 
     { 
      // Do something with object of type A 
      Console.WriteLine($"a.Value: {a.Value}"); 
     } 
     else 
     { 
      // Must be a B. Do something with object of type B 
      B b = (B)o; 

      Console.WriteLine($"b.Value: {b.Value}"); 
     } 
    } 
} 

static IEnumerable<int> RandomOrderedSequence(Random random, int max, int count) 
{ 
    return RandomSequence(random, max, count).OrderBy(i => i); 
} 

static IEnumerable<int> RandomSequence(Random random, int max, int count) 
{ 
    while (count-- > 0) 
    { 
     yield return random.Next(max); 
    } 
} 

In Ihrem Fall, Sie würden natürlich Typen A und B mit den Typen ersetzen Sie wirklich sind Verwenden Sie, stellen Sie geeignete Selektoren bereit, und führen Sie dann mit jeder Instanz, die als die zusammengeführte Reihenfolge in der Reihenfolge zurückgegeben wird, das aus, was Sie möchten.

Beachten Sie, dass selbst wenn die Typen sich als eine gemeinsame Basis herausstellen, für die sie verglichen und zusammengeführt werden können, würde ich immer noch eine Merge-Sortierung über einfache Verkettung und Zusammenführung des Ergebnisses empfehlen. Die Merge-Sortierung ist ein viel effizienterer Weg, um bereits geordnete Daten in einer einzigen Sequenz von geordneten Daten zusammenzuführen.

+0

Hut ab vor deiner Meisterschaft. Es wirkt wie ein Zauber. Tolle Arbeit und vielen Dank, elegante Lösung. – Gondil

0

Sie benötigen die Listen, um eine gemeinsame Schnittstelle zu implementieren, damit sie verglichen werden können. Zum Beispiel:

public interface ISynchronizable 
{ 
    long GetTicks(); 
} 

Sie müssen also die beiden Objekte zu implementieren, dies haben, etwa so:

public class Fixation : ISynchronizable 
{ 
    public long GetTicks() 
    { 
     // get the ticks 
    } 
    // some other code 
} 

public class TextChange: ISynchronizable 
{ 
    public long GetTicks() 
    { 
     // get the ticks 
    } 

    // some other code 
} 

Dann würde die Ergebnisliste wie folgt erstellt werden:

public List<ISynchronizable> list = new List<ISynchronizable>(); 
list.AddRange(fixationList); 
list.AddRange(textChangeList); 
resultList = list.OrderBy(e => e.GetTicks()).ToList(); 
+0

Danke für die Antwort, ich werde es später versuchen :) – Gondil

Verwandte Themen