2011-01-06 13 views
3

Ich habe 3 Listen, die eine willkürliche Anzahl von Doppel enthalten. Jetzt möchte ich diese Listen miteinander vergleichen und sortieren. Alle Listen haben die gleiche Länge.Sortieren 3 Liste nach ihren Werten

Die Beziehung von Sortierung ist:

jedes Element vergleichen. Die Liste, die mehr Elemente hat, die größer als die andere sind, ist höher geordnet. Ich habe eine Implementierung für zwei Listen geschrieben:

public static bool isGreater(List<double> first, List<double> second) 
     { 
      int firstCounter = 0; 
      int secondCounter = 0; 

      for (int i = 0; i < first.Count; i++) 
      { 
       if (first.ElementAt(i) > second.ElementAt(i)) 
       { 
        firstCounter++; 
       } 
       else if (first.ElementAt(i) < second.ElementAt(i)) 
       { 
        secondCounter++; 
       } 
      } 

      if (firstCounter > secondCounter) 
      { 
       return true; 
      } 
      else 
      { 
       return false; 
      } 
     } 

Aber wie kann ich diesen Code für 3 oder sogar n Listen anpassen?

+0

Sie wollen nur wissen, welche Liste mehr größere Werte hat? – BrunoLM

+0

ja, genau! . –

+0

Hast du meine Antwort gesehen? –

Antwort

2

Sie sollten in der Lage sein zu tun, Dies verwendet LINQ und einen benutzerdefinierten IComparer für IEnumerable<double>.

public class EnumerableDoubleComparer : IComparer<IEnumerable<double>> 
{ 
    public int Compare(IEnumerable<double> a, IEnumerable<double> b) 
    { 
     var counts = a.Select((k,i) => new { Value = k, Index = i }) 
         .Join(b.Select((k,i) => new { Value = k, Index = i }), 
          outer => outer.Index, 
          inner => inner.Index, 
          (outer,inner) => outer.Value > inner.Value 
                ? "A" 
                : (inner.Value > outer.Value 
                 ? "B" 
                 : "")) 
         .GroupBy(listID => listID) 
         .Select(g => new { g.Key, Count = g.Count() }); 

     // you could also use SingleOrDefault on the collection and check for null 
     var aCount = counts.Where(c => c.Key == "A") 
          .Select(c => c.Count) 
          .SingleOrDefault(); 
     var bCount = counts.Where(c => c.Key == "B") 
          .Select(c => c.Count) 
          .SingleOrDefault(); 

     return aCount - bCount; 
    } 
} 

als:

var a = new double[] { 1, 1 }; 
var b = new double[] { 2, 2 }; 
var c = new double[] { 3, 3 }; 

var lists = new List<IEnumerable<double>> { a, c, b }; 

var ordered = lists.OrderByDescending(l => l, new EnumerableDoubleComparer()); 
+0

FYI ... Ich verwende ein Verständnis, das {1,3}, {2,2}, {3,1} als gleichwertig betrachten würde, da jedes ein Element größer als und ein Element kleiner als das Element an der entsprechenden Position in jeder der anderen Listen. – tvanfosson

+0

+1 für die Implementierung in einem IComparer. – Didaxis

0

Die Vielzahl der Listen ist eine Illusion - es gibt nur eine Liste, aber jedes Element hat ein Attribut, das angibt, aus welcher Liste es kommt.

Die Listen zusammenführen, sortieren und dann in ihre ursprünglichen Listen zurückspalten.

2

Was Sie tun müssen, sortieren() eine Auflistung von Listen basierend auf Ihrer Definition der Bestellung. Sie sollten in der Lage sein, die Standardsortierung zu verwenden und Ihre benutzerdefinierte Bestellfunktion zu liefern.

Algorithmus wäre so etwas wie:

  1. Erstellen Sie eine Reihe von Listen, die Sie sortieren möchten.
  2. Rufen Sie die Standardmethode sort() für Arrays auf, verwenden Sie die oben definierte Routine als Komparatorfunktion.

EDIT: Dieser Algorithmus sollte Ihnen das Maximum in O geben (M N lgN) (N Listen jeder der Größe M). Ich kenne einen etwas schnelleren (logarithmischen Faktoren) randomisierten Algorithmus, um den max. Sie können darüber lesen here. Ich würde nicht empfehlen, diesen Algorithmus zu implementieren, es sei denn, Sie haben eine enorm große Anzahl von zu verarbeitenden Listen.

1

Erstens wäre es nicht einfacher, eine Sammlung zu verwenden, die bereits sortiert ist?

Sie können dazu a Sorted Dictonary verwenden.

In Bezug auf Ihre Frage, wie Sie es auf n-Listen anwenden Rekursion verwenden Sie einfach eine Sammlung und verfolgen Sie das letzte Ergebnis. So können Sie beispielsweise die erste und die dritte Liste vergleichen, wenn das Ergebnis der ersten Wiederholung Ihrer rekursiven Funktion die erste Liste zurückgibt.

1

Verwenden Sie ein Array, um Zähler für jede Liste zu halten.

Wenn Sie n Listen haben. Ihr Array Counter

void SortLists(List<List<double>> lists) 
{ 
int[] counter = new int[lists.Count]; 

for (int i = 0; i < lists[0].Count; i++) 
{ 
    double MaxValue = double.MinValue; 
    int winningList = 0; 

    for (int j = 0; j < lists.Count; j++) 
    { 
     if(lists[j].ElementAt(i) > MaxValue) 
     { 
      MaxValue = lists[j].ElementAt(i); 
      winningList = j; 
     } 
    } 

    counter[winningList]++; 
} 

// sort the counter array, in effect your lists are sorted. 
} 
+0

aber es wird erwähnt, dass alle Listen gleich groß sind :), sonst bleiben die Fragen sowieso nicht. –

+0

Ich bemerke gerade ein Problem, das Sie Listen [0] mit sich selbst vergleichen, die nicht korrektes Verhalten ist. Ich habe meinen anderen Kommentar losgeworden, denn nach einem zweiten Blick vergleicht er die ersten Listen mit den anderen Listen, die sich selbst enthalten. –

1
var list11 = new List<double> { 1, 2, 3 }; 
var list22 = new List<double> { 4, 5, 3 }; 
var list33 = new List<double> { 4, 1, 0 }; 

int acounter = 0, bcounter = 0, ccounter; 
list11.Select((o, i) => new { a = list11[i], b = list22[i] }) 
    .Aggregate(0, (init, item) => item.a > item.b 
             ? acounter++ 
             : item.a == item.b 
              ? bcounter 
              : bcounter++); 
if (acounter > bcounter) 
{ 
    //Do the same for list11 and list33 
} 
else 
{ 
    //Do the same for list22 and list33 
} 

you can refactor it and write a function for two list and call that for every pair that you want.

1

Ich habe eddited nur ein wenig Ihre Methode und fügte ein anderer:

private static List<double> GetGreater(List<double> first, List<double> second) 
{ 
    int firstCounter = 0; 
    int secondCounter = 0; 

    for (int i = 0; i < first.Count; i++) 
    { 
     if (first.ElementAt(i) > second.ElementAt(i)) 
     { 
      firstCounter++; 
     } 
     else if (first.ElementAt(i) < second.ElementAt(i)) 
     { 
      secondCounter++; 
     } 
    } 

    // return the greater list instead of bool 
    return (firstCounter > secondCounter ? first : second); 
} 


public static List<double> Greater(params List<double>[] p) 
{ 
    // assumes the first list is the greater, then check the others 
    // this method assumes you will always pass at least 2 lists 

    List<double> greater = p[0]; 

    for (var i = 1; i < p.Length; ++i) 
    { 
     greater = GetGreater(greater, p[i]); 
    } 

    return greater; 
} 

static void Main(string[] args) 
{ 
    // lists used for this test 
    var l1 = new List<double>() { 1, 222, 3 }; 
    var l2 = new List<double>() { 1, 2, 4 }; 
    var l3 = new List<double>() { 11, 222, 333 }; 

    var l4 = Greater(l1, l2, l3); // l3 
} 
1

Es klingt für mich wie Sie eine haben "äußere" Liste der "inneren" Listen, und Sie möchten die "äußere" Liste sortieren.Sie können das tun:

// Set up some input data 
var outerList = new List<List<double>>(); 
outerList.Add(new List<double> { 2.0, 3.0, 3.0 }); 
outerList.Add(new List<double> { 1.0, 2.0, 3.0 }); 
outerList.Add(new List<double> { 2.0, 2.0, 3.0 }); 

// Sort the outer list 
outerList.Sort((first, second) => isGreater(first, second) ? 1 : -1); 

Eigentlich würden Sie wahrscheinlich besser dran zu ändern ist größer (die keine „beide Listen sind gleich“ Ergebnis zurückgeben kann, was Sortieren verwirren könnte) zu einer CompareLists Funktion, die den Wert -1 zurück Wenn das erste Argument kleiner als das zweite ist, 1, wenn das erste Argument größer als das zweite ist, und 0, wenn sie gleich sind. Dann könnten Sie rufen Sie einfach an:

outerList.Sort(CompareLists); 
1

Solange die Anzahl der Elemente in jeder Liste die gleiche ist und bekannt ist, hier ist ein kleines Beispiel I aufgearbeitet:

const int listSize = 6; 

List<int> one = new List<int> { 0, 1, 2, 3, 4, 5 }; 
List<int> two = new List<int> { 10, 1, 9, 2, 8, 3 }; 
List<int> three = new List<int> { 5, 5, 5, 5, 5, 5 }; 

Dictionary<List<int>, int> lists = new Dictionary<List<int>, int>() 
{ 
    {one, 0}, 
    {two, 0}, 
    {three, 0} 
}; 

for (int i = 0; i < listSize; i++) 
{ 
    var sortedAtIndex = lists.Keys.OrderByDescending(k => k[i]); 
    lists[sortedAtIndex.ElementAt(0)]++; 
} 

// And to show you that it works... 
foreach (var element in lists.OrderByDescending(k => k.Value) 
    .Select(k => k.Key)) 
{ 
    Console.WriteLine("{0}", lists[element]); 
} 
+0

Eine Sache, die ich nicht berücksichtigt habe, weil es in Ihrer Anforderung unklar ist, ist, wenn mehrere Listen den größten Wert für einen bestimmten Durchlauf teilen (wie im letzten Durchgang meines Beispiels). Es wäre trivial, dies zu erklären, und das überlasse ich Ihnen. – Didaxis

Verwandte Themen