2017-06-02 5 views
1

Bear mit mir, ich werde versuchen, dies nicht zu kompliziert zu machen. Ich habe eine Liste von Produkten. Ein Produkt wie folgt aussieht:C# Sortieren mit mehreren Bedingungen

{ 
    "id": 3797, 
    "title": "Canon EOS 100D Digital SLR Camera with 18-55 IS STM Lens, HD 1080p, 18MP, 3\" LCD Touch Screen", 
    "shortTitle": "Canon EOS 100D Black", 
    "brand": "Canon", 
    "model": "EOS 100D", 
    "colour": "Black", 
    "gtin": "8714574602721", 
    "image": "http://piiick.blob.core.windows.net/images/Canon-EOS-100D-18-55-Black-8714574602721.png", 
    "type": "Digital SLR", 
    "lensFocalLength": "18-55", 
    "lensType": "IS STM", 
    "lensMount": "EF/EF-S", 
    "maxAperture": "999", 
    "connectivity": "", 
    "shootingModes": "Scene Intelligent Auto (Stills and Movie), No Flash, Creative Auto, Portrait, Landscape, Close-up, Sports, SCN(Kids, Food, Candlelight, Night Portrait, Handheld Night Scene, HDR Backlight Control), Program AE , Shutter priority AE, Aperture priority AE, Manual (Stills and Movie)", 
    "weight": 410.0, 
    "width": 116.8, 
    "height": 90.7, 
    "depth": 69.4, 
    "digitalZoom": "N/A", 
    "opticalZoom": "N/A", 
    "waterproof": false, 
    "maxVideoResolution": "1920 x 1080", 
    "sensorType": "CMOS", 
    "sensorSize": "22.3 x 14.9 mm", 
    "continuousShootingSpeed": "4", 
    "iso": "1600", 
    "style": "traditional", 
    "designer": "", 
    "dateAnnounced": "10/06/2008", 
    "focusPoints": 7 
} 

Aber um dies zu erklären zu helfen, ich es vereinfachen. Ich versuche, eine Sortiermethode zu erstellen, die das Sortieren nach mehreren Spalten ermöglicht. Zum Beispiel habe ich diese Methode:

/// <summary> 
/// Performs an advanced sort on products using sortations 
/// </summary> 
/// <param name="products">The products to sort</param> 
/// <param name="sortations">The sortation list</param> 
public void AdvancedSort(List<JObject> products, List<Sortation> sortations) 
{ 

    // Get our value types 
    GetTypesFromOperator(sortations); 

    // Sort our products by the sortations 
    products.Sort((a, b) => 
    { 
     foreach (var sortation in sortations) 
     { 

      // Get our values 
      var fieldName = sortation.Field; 
      var x = a.SelectToken(fieldName).ToString(); 
      var y = b.SelectToken(fieldName).ToString(); 
      var type = sortation.Type; 

      // If both values are the same, skip the rest of this iteration 
      if (x.Equals(y)) return 0; 

      // If we have an expression 
      if (!string.IsNullOrEmpty(sortation.Expression)) 
      { 

       // If we are checking for between 
       if (sortation.Operator == "><") 
       { 

        // Get our values 
        var values = sortation.Expression.Split(','); 

        // If we have 2 values 
        if (values.Length == 2) 
         return CompareBetween(values, x, y); 
       } 

       // If we are checking booleans 
       if (sortation.Operator == "===") 
        return CompareBoolean(sortation.Expression); 

       // If we are checking equals 
       if (sortation.Operator == "=") 
        return y.Equals(sortation.Expression) ? 1 : -1; 

       // If we are checking like 
       if (sortation.Operator == "%") 
        return y.Equals(sortation.Expression, StringComparison.OrdinalIgnoreCase) ? 1 : -1; 
      } 

      // If we get this far, do a switch on sortation types 
      switch (sortation.Type) 
      { 
       case SortationValueType.Boolean: 
        return Boolean.Parse(x) ? -1 : 1; 
       case SortationValueType.Number: 
        return CompareNumeric(x, y, sortation.Direction); 
       default: 
        return string.CompareOrdinal(x, y); 
      } 
     } 

     // If nothing matches, return 0 
     return 0; 
    }); 
} 

Es wird versucht, basierend auf Eigenschaft Werttypen zu sortieren und was ich sortations. Eine Sortierung ist nur eine Klasse, die den Operator, den Ausdruck und das Feld für die Abfrage festlegt. Dies ist ein Beispiel für eine Sortierungs:

// Add importance, expert and sponsored 
sortations.Add(new Sortation 
{ 
    Field = "importance", 
    Operator = "<" 
}); 

Jetzt können wir eine Reihe von verschiedenen sortations haben, die dynamisch hinzugefügt werden. Ich muss in der Lage sein, die Produkte nach diesen Sortierungen zu sortieren. Ich habe einen einfachen Test erstellt:

[Test] 
public void SortBySilverColourSilverShouldBeTop() 
{ 

    // Assemble 
    var json = "[{ colour: 'Black', importance: '150' }, { colour: 'Black', importance: '150' }, { colour: 'Black', importance: '150' }, { colour: 'Silver', importance: '150' }, { colour: 'Black', importance: '149' }, { colour: 'Black', importance: '149' }, { colour: 'Black', importance: '149' }, { colour: 'Silver', importance: '149' }]"; 
    var products = JsonConvert.DeserializeObject<List<JObject>>(json); 
    var sortations = new List<Sortation>() { new Sortation() { Field = "colour", Operator = "=", Expression = "Silver" }, new Sortation() { Field = "importance", Operator = "<" } }; 

    // Act 
    _sortProvider.AdvancedSort(products, sortations); 
    var result = products[0].SelectToken("colour").ToString(); 

    // Assert 
    Assert.That(result, Is.EqualTo("Silver")); 
} 

ich damit rechnen würde, dass ich diese Ausgabe erhalten würde:

[ 
    { colour:'Silver', Importance:'150'}, 
    { colour:'Black', Importance:'150' }, 
    { colour:'Black', Importance:'150' }, 
    { colour:'Black', Importance:'150' }, 
    { colour:'Silver', Importance:'149' }, 
    { colour:'Black', Importance:'149' }, 
    { colour:'Black', Importance:'149' }, 
    { colour:'Black', Importance:'149' } 
] 

sondern bekomme ich diese Ausgabe:

[ 
    { colour:'Silver', Importance:'150' }, 
    { colour:'Silver', Importance:'149' }, 
    { colour:'Black', Importance:'150' }, 
    { colour:'Black', Importance:'150' }, 
    { colour:'Black', Importance:'150' }, 
    { colour:'Black', Importance:'149' }, 
    { colour:'Black', Importance:'149' }, 
    { colour:'Black', Importance:'149' } 
] 

Can jemand hilft mir meine Sortiermethode zu reparieren?

+0

Diese Art von Zeug ist wirklich einfach, wenn die Daten in einer Art Datenbank sind, und Sie werden eine bessere Leistung auf diese Weise als manuell sortieren nach der Tatsache erhalten. Wenn diese Daten ursprünglich aus einer Datenbank stammen, sollten Sie Ihre Sortierungen besser in einen Teil einer Abfrage konvertieren. Wenn es nicht aus einer Datenbank stammt, könnten Sie es in eine Datenbank aufnehmen. – ashbygeek

+0

Es kommt von einer API daher, warum es alles in JSON ist: D – r3plica

Antwort

2

In meinem Kopf Ihr grundsätzliches Problem ist, dass, sobald der erste Sortierungs ein Spiel trifft es die Sortierreihenfolge Wert auf die Sortierfunktion zurückgibt und den Rest die Sortierung spielt überhaupt keine Rolle. Ich glaube, was Sie tun müssen, Swap ist die foreach und der products.sort Anruf, etwa so:

// Get our value types 
GetTypesFromOperator(sortations); 

foreach (var sortation in sortations) 
{ 
    // Sort our products by the sortations 
    products.Sort((a, b) => 
    { 
     // Get our values 
     var fieldName = sortation.Field; 
     var x = a.SelectToken(fieldName).ToString(); 
     var y = b.SelectToken(fieldName).ToString(); 
     var type = sortation.Type; 
     .... 
     .... 
    } 
} 

Dies wird länger dauern, aber jeder Sortier- berücksichtigt. Beachten Sie, dass die letzte Sortierung in der Liste die wichtigste ist.

+0

, die funktioniert, wie viel langsamer reden wir, denkst du? Ich werde nie mehr als 200 Produkte und wahrscheinlich nicht mehr als 3 Sortierungen haben – r3plica

+0

Bei diesen Größen nicht langsam genug, um Sie zu stören. Die zusätzlichen Sortierungen verursachen die meisten Probleme, da selbst die effizientesten Sortieralgorithmen eine Menge Berechnungen benötigen, aber mit höchstens 3 von ihnen können Sie erwarten, dass sie nur 3 mal länger als Ihr Original dauert. – ashbygeek

1

Es sieht so aus, als ob Sie sie rückwärts haben - es setzt alle "Silver" s zuerst, dann Reihenfolge nach Wichtigkeit Sekunde.

Versuchen Sie die Reihenfolge Ihrer sortations Swapping:

var sortations = new List<Sortation>() { 
    new Sortation() { Field = "importance", Operator = "<" }, 
    new Sortation() { Field = "colour", Operator = "=", Expression = "Silver" } 
}; 
+0

Wenn ich das tue, landen die "Silver" Produkte am Ende jeder Wichtigkeit Block – r3plica

+0

in der Tat, es kommt nie auf die zweite Sortierung – r3plica