2012-04-06 21 views
1

Ich schrieb die Funktion mit js + jQuery. HierSchlechte Leistung mit einer JavaScript + jQuery-Funktion, um Tabellenzeilenredundanz zu überprüfen

ist ein Link zu einer jsFiddle, die mein Problem zeigt: http://jsfiddle.net/anarnold/LpBaW/

Das Ziel dieser Funktion ist es, eine Tabelle zu scannen und überprüfen für die Zeilen, die bestimmte Feld haben (td) Anpassungswerte. Den Zeilen wird dann eine Klasse zugewiesen, die angibt, ob sie eindeutig sind oder nicht, und die Anzahl übereinstimmender Zeilen wird in das letzte Feld (td) jeder Zeile gedruckt.

Es nutzt im Grunde eine verschachtelte Schleife dieser Struktur:

Für jede Zeile ... scannen die gesamte Tabelle für die Spiele ..

Die Art, wie ich Zeilen identifizieren, ist das Feld (td) verketten Texte aus jeder Zeile in ein Rowid-Attribut im Endfeld (td) für jede Zeile.

Die aktuelle Funktion funktioniert gut, aber es wird sehr langsam mit großen Tabellen ~ 2000 Zeilen.

Es muss einen effizienteren und eleganteren Weg geben, dies zu erreichen. Jede Hilfe würde sehr geschätzt werden!

+0

'$ ("# Binning tbody") Kinder ('tr')' -. Warum nicht '$ (" # Binning tbody > tr ")'? – ThiefMaster

+0

Danke. Es ist definitiv sauberer, aber keine spürbare Leistungsverbesserung. – anarnold

Antwort

2

ist ein Beispiel für eine assoziative Array unter Verwendung der Ergebnisse zu speichern und dann auf iterieren, dass:

http://jsfiddle.net/AdDMk/

var rowIdCnt = {}; 

function unqOrMsgTest() { 
    // Store counts here 
    var rowIdCnt = {}; 

    // loop through check tds 
    $("#binning tr td[col=check]").each(function() { 

     // grab row identifer to check against other rows   
     var rowId = $(this).attr("rowid"); 

     if (rowId in rowIdCnt) { 
      rowIdCnt[rowId] ++; 
     } else { 
      rowIdCnt[rowId] = 1; 
     } 

    }); 

    // Now iterate over each count and update the table appropriately: 
    $.each(rowIdCnt, function(rowId, cnt) { 
     //this bit of logic picks a class to assign rows   
     var resultClass = "notUnique"; 
     if (cnt < 2) { 
      resultClass = "unique"; 
     } 

     //apply the row class and print the redundancy number into td 
     $('#binning tr td[rowid='+rowId+']').text(cnt).parent().addClass(resultClass); 

    }); 

} 
+0

Vielen Dank. Sobald ich es geschrieben sehe, scheint es offensichtlich! Ich werde diesen Ansatz jetzt benchmarken und mit Ergebnissen zurückschreiben! – anarnold

+0

führt in ungefähr 750ms auf der gleichen Tabelle aus, die meine Funktion 45sec nahm. – anarnold

0

Erstellen Sie Hashwerte für jeden Tabelleneintrag und verwenden Sie Hashtabellen oder sortieren Sie diese, bevor Sie nach Duplikaten suchen. Sie müssen also nur Nachbarn vergleichen.

+0

Dies scheint ein viel besserer Ansatz! Ich arbeite jetzt daran. Meine Fließgewohnheit ist immer noch ziemlich niedrig. Kann jemand ein paar Zeilen Code löschen, die zeigen, wie Hashes in js verwendet und sortiert werden? – anarnold

+0

@ Jeff B gab eine nette Hash-Tabelle Beispiel, der Sortieransatz hängt wirklich von Ihrer Tabelle und welche Felder zu vergleichen – worenga

0

Eine elegantere Möglichkeit besteht darin, dies auf der Datenebene zu tun, bevor Sie diese Tabelle erstellen. Hier

+0

Danke, vucetica. Die Tabelle ist dynamisch; es wird wiederholt über Ajax-Aufrufe angehängt. Kein direkter Zugriff auf Daten, daher muss es von der Tabelle kommen. @ Mightyuhu schlug vor, Daten in einen Hash zu extrahieren und dann damit zu arbeiten. Versuche jetzt seine Annäherung. – anarnold

+0

Wenn Sie Daten über Ajax anhängen, ist es noch einfacher. Fügen Sie vor dem Hinzufügen nur Zeilen hinzu, die in Ihrer Tabelle nicht vorhanden sind. Auf diese Weise (für Ihr Beispiel) werden Sie 2000 mal durch Ihren Tisch und 4 000 000 mal durch Ihr Javascript-Array passieren, was viel schneller ist, als Ihren Tisch 4 000 000 Mal zu passieren. –

1

Hier ist eine bessere Vorformung Methode, dies zu tun. Ich habe so viele redundante DOM entfernt nennt, wie ich so korrigiert, wie gut könnte die ungültigen Attribute (HTML-Tags können nur bestimmte Attribute unterstützen .. benutzerdefinierte Attribute mit data- werden Präfix müssen)

$(document).ready(function(){ //this is just to fire the function 
    $("#unqOrMsgTestFire").click(function(){ 
     unqOrMsgTest(); 
    }); 
}); 

function check_unique(row, collection) { 
    var unique = true, rowid = $(row).children('td[data-col=check]')[0].getAttribute('data-rowid'); 
    collection.each(function() { 
     if($(this).children('td[data-col=check]')[0].getAttribute('data-rowid') == rowid) { 
      unique = false; 
     } 
    }); 
    return unique; 
} 

function unqOrMsgTest() { 

    var collection = $("#binning tbody").children('tr'); 

    collection.each(function(i, el){ 
     el.className += check_unique(el, collection.not(el)) ? ' unique' : 'notUnique'; 
    });    

}​ 

http://jsfiddle.net/rlemon/LpBaW/41/ < - sie alle scheitern aber das ist zu erwarten.

+0

Ich habe gerade meine mit 2000 Zeilen getestet und es scheitert schrecklich. – rlemon

+0

Ich respektiere die Ehrlichkeit, und ich werde definitiv Ihr Feedback re implementieren. illegale Attribute ... (Dies ist nur für ein internes Test-Tool, also muss es nicht standardkonform und semantisch perfekt sein, aber es ist eine gute Übung, dies trotzdem zu tun =) – anarnold

+0

@rlemon: während dieser Code lesbarer ist, Es wird immer noch eine verschachtelte Schleife ausgeführt, so dass die Leistung nicht sehr unterschiedlich sein wird und somit fürchterlich ausfallen wird. –

0

Hier ist meine empfohlene Lösung:

http://jsfiddle.net/j9RXR/29/

function unqOrMsgTest() { 
    var rows = $("#binning tbody").children('tr'); 
    var totalRows = rows.length; 
    var idLookup = {}; 
    var i, rowId, resultClass, checkColumn, rowCount, row; 

    // loops through all rows, convert to jQuery objects and track the IDs 
    for (i = 0; i < totalRows; i++) 
    { 
     row = $(rows[i]); 
     rowId = row.children('td[col="check"]').attr("rowid"); 
     rows[i] = row; 

     idLookup[rowId] = (rowId in idLookup) ? idLookup[rowId] + 1 : 1; 
    } 

    // loop through each row and check them for redundancy 
    for (var i = 0; i < totalRows; i++) 
    { 
     // grab row identifer to check against the id lookup 
     row = rows[i]; 
     checkColumn = row.children('td[col="check"]'); 
     rowId = checkColumn.attr("rowid");  

     //this bit of logic picks a class to assign rows   
     rowCount = idLookup[rowId]; 
     resultClass = rowCount < 2 ? "unique" : "notUnique"; 

     //apply the row class and print the redundancy number into td 
     checkColumn.text(rowCount); 
     row.attr("class", resultClass);   
    };    
}​ 

ähnlich wie bei den oben Antworten, die ein assoziatives Array (oder Hash) schlagen vor, mit dem IDs und zählt zu speichern, habe ich auch alle Anrufe entfernt zu list.each(function() {...}) und die Anzahl der Konvertierungen von dom-Elementen in jQuery-Objekte minimiert.

Der Grund, warum ich die Verwendung von each entfernt habe, ist, weil eine neue anonyme Funktion bei jeder Iteration erstellt wird, auch redundante Konvertierungen von diesem zu $ ​​(this) wurden aufgerufen, ganz zu schweigen von der Stack Thrashing. Es genügt zu sagen, dass eine einfache for-Schleife benötigt wird und viel schneller ist.

Für mehr auf jQuery Fallen überprüfen jQuery pitfalls to avoid

+0

Das ist interessant. Wenn ich jedoch Ihren Code mit 5000 Elementen vergleiche, erhalte ich eine Laufzeit von 1390 Millisekunden, und wenn ich meinen Code mit ".each()" benchmarkiere, erhalte ich eine Laufzeit von 194 Millisekunden. Ich frage mich, ob Ihre zusätzlichen jQuery Add Overhead hinzufügen? –

+0

Interessant in der Tat :) Welchen Browser benutzen Sie? Ich kann selbst mit Ihrer Lösung nicht annähernd 194 Millisekunden erreichen. Ich habe das Sample hier aktualisiert: http://jsfiddle.net/j9RXR/35/, um beide Lösungen einzubeziehen, und auf Win7 mit Chrome. Ich bekomme deine Lösung ungefähr doppelt so langsam:/Ich muss das überprüfen in das ein bisschen mehr! –

+0

Ich fand auch anständige Leistungsgewinne durch harte Kodierung (ich weiß, ich weiß ...) Spalten. Zum Beispiel anstelle von 'checkColumn = row.children ('td [col =" check "]');' Dies scheint viel schneller zu sein 'checkColumn = row.children() [5];' –

0

http://jsfiddle.net/LpBaW/57/

$(function(){ //this is just to fire the function 
    $("#unqOrMsgTestFire").click(unqOrMsgTest); 
    $("#spawn").click(function(){ 
     var blueprint = $("#binning tbody tr").first(); 
     for(var i = 0; i < 1000; i++) 
      blueprint.clone().appendTo("#binning tbody").find('td[rowid]').attr('rowid', Math.floor(Math.random()*500)); 
    }); 
}); 

function unqOrMsgTest() { 
    console.profile(); 
    var toCheck = $("#binning > tbody > tr > td[col=check]"), 
     ignore = {}, 
     curId, 
     currentlyProcessing, 
     rowsAmount, 
     i; 

    i = toCheck.length - 1; 
    while(i >= 0) { 
     curId = toCheck.eq(i).attr("rowid"); 
     if(!(curId in ignore)) { 
      ignore[curId] = undefined; 

      currentlyProcessing = $("#binning > tbody > tr > td[rowid=" + curId + "]"); 

      rowsAmount = currentlyProcessing.length; 

      currentlyProcessing 
       .text(rowsAmount) 
       .parent().attr('class', rowsAmount > 1 ? "notUnique" : "unique"); 
     } 
     i--; 
    } 
    console.profileEnd(); 
}​ 

     rowsAmount = currentlyProcessing.length; 

     currentlyProcessing 
      .text(rowsAmount) 
      .parent().attr('class', rowsAmount > 1 ? "notUnique" : "unique"); 

     toCheck = toCheck.not(currentlyProcessing); 
    } 
}