[JS] sorteren op Class

Pagina: 1
Acties:

Vraag


Acties:
  • 0 Henk 'm!

  • Niekleair
  • Registratie: Oktober 2006
  • Laatst online: 11-06-2024
Hallo allemaal,

Ik heb een tabel met daarin tijdstippen in een periode van circa 28 uur. In de tabel zelf moeten alleen de tijdstippen zichtbaar zijn; maar deze moeten gestorteerd worden op basis van een timedelta (tijd vanaf een bepaald tijdstip). De timedelta is opgenomen in een class (het is geen ID omdat er de kans bestaat dat in de tabel het zelfde tijdstip meerdere keren voor gaat komen). In de uiteindelijke versie zullen niet meer dan 200 rijen komen.

Kan ik de tabel sorteren op basis van de waarde van class? En bied de sort methode op de website van W3 schools dan uitkomst?

Ik heb hun tabel een beetje verbouwd voor mijn voorbeeld, de rest komt rechtstreeks van W3schools.com


HTML:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
<!DOCTYPE html>
<html>
<head>
<title>Sort a HTML Table Alphabetically</title>
<style>
table {
  border-spacing: 0;
  width: 100%;
  border: 1px solid #ddd;
}

th, td {
  text-align: left;
  padding: 16px;
}

tr:nth-child(even) {
  background-color: #f2f2f2
}
</style>
</head>
<body>

<p>Click the button to sort the table alphabetically, by name:</p>
<p><button onclick="sortTable()">Sort</button></p>

<table id="myTable">
  <tr>
    <th>Time</th>
    <th>Description</th>
  </tr>
  <tr>
    <td class="43200">12:00:00</td>
    <td>offline at noon</td>
  </tr>
  <tr>
    <td class="28805">08:00:05</td>
    <td>offline in the morning</td>
  </tr>
  <tr>
    <td class="75600">21:00:00</td>
    <td>offline in the evening</td>
  </tr>
  <tr>
    <td class="39600">11:00:00</td>
    <td>also offline in the morning</td>
  </tr>
  <tr>
    <td class="94822">02:20:22</td>
    <td>offline somewhere after midnight (next day)</td>
  </tr>
  <tr>
    <td class="85632">23:47:12</td>
    <td>also offline in the evening</td>
  </tr>
</table>

<script>
function sortTable() {
  var table, rows, switching, i, x, y, shouldSwitch;
  table = document.getElementById("myTable");
  switching = true;
  /*Make a loop that will continue until
  no switching has been done:*/
  while (switching) {
    //start by saying: no switching is done:
    switching = false;
    rows = table.rows;
    /*Loop through all table rows (except the
    first, which contains table headers):*/
    for (i = 1; i < (rows.length - 1); i++) {
      //start by saying there should be no switching:
      shouldSwitch = false;
      /*Get the two elements you want to compare,
      one from current row and one from the next:*/
      x = rows[i].getElementsByTagName("TD")[0];
      y = rows[i + 1].getElementsByTagName("TD")[0];
      //check if the two rows should switch place:
      if (x.innerHTML.toLowerCase() > y.innerHTML.toLowerCase()) {
        //if so, mark as a switch and break the loop:
        shouldSwitch = true;
        break;
      }
    }
    if (shouldSwitch) {
      /*If a switch has been marked, make the switch
      and mark that a switch has been done:*/
      rows[i].parentNode.insertBefore(rows[i + 1], rows[i]);
      switching = true;
    }
  }
}
</script>

</body>
</html>


als
JavaScript:
1
 if (x.innerHTML.toLowerCase() > y.innerHTML.toLowerCase()) {


aangepast kan worden dat deze de waardes van de classes vergelijkt dan ben ik er.

Mocht het niet mogelijk zijn, is een andere optie om de 'timedeltas' te importeren, vervolgens te sorteren en daarna de weergave aan te passen naar HH:MM:SS.

[ Voor 0% gewijzigd door Niekleair op 12-12-2020 04:22 . Reden: slordigheidjes uit de code gehaald ]

[img]error.jpg[/img]

Beste antwoord (via Niekleair op 12-12-2020 09:23)


  • Daos
  • Registratie: Oktober 2004
  • Niet online
Met x.className haal je de class op. Zie: https://developer.mozilla...Web/API/Element/className

Is wel een string. Als je getallen altijd 5 cijfers zijn is dat geen probleem. Anders moet je een nummer (number) maken van beide kanten van de >. Standaard js-truc is een + ervoor. Dus +x.className.

Alle reacties


Acties:
  • Beste antwoord
  • 0 Henk 'm!

  • Daos
  • Registratie: Oktober 2004
  • Niet online
Met x.className haal je de class op. Zie: https://developer.mozilla...Web/API/Element/className

Is wel een string. Als je getallen altijd 5 cijfers zijn is dat geen probleem. Anders moet je een nummer (number) maken van beide kanten van de >. Standaard js-truc is een + ervoor. Dus +x.className.

Acties:
  • +1 Henk 'm!

  • GlowMouse
  • Registratie: November 2002
  • Niet online
Het is mooier om hiervoor een dataveld te gebruiken.

De waarde haal je dan op met parseInt(x.getAttribute("data-timedelta")).

Acties:
  • +1 Henk 'm!

  • Niekleair
  • Registratie: Oktober 2006
  • Laatst online: 11-06-2024
Thanks.

Heb het voor nut met de className opgelost. Eerst werkte het niet; maar na wat trouble-shooten bleek ik de beginnersfout gemaakt te hebben.. index begint met 0...

[img]error.jpg[/img]


Acties:
  • 0 Henk 'm!

  • DJMaze
  • Registratie: Juni 2002
  • Niet online
Anno 2020:

code:
1
2
3
4
5
6
[...document.querySelectorAll('#myTable td:first-child')].sort((a, b) => {
    const i = a.className.localeCompare(b.className);
    if (i == -1) a.parentNode.after(b);
    if (i == 1) a.parentNode.before(b);
    return i;
});


Niet getest! Zit op mobiel te typen

Maak je niet druk, dat doet de compressor maar


Acties:
  • 0 Henk 'm!

  • Daos
  • Registratie: Oktober 2004
  • Niet online
Kan je trouwens niet al sorteren op je server? Dus dat je een gesorteerde tabel genereert? Lijkt mij mooier dan rommelen met javascript.

Acties:
  • 0 Henk 'm!

  • R4gnax
  • Registratie: Maart 2009
  • Laatst online: 06-09 17:51
DJMaze schreef op zaterdag 12 december 2020 @ 09:38:
Anno 2020:

code:
1
2
3
4
5
6
[...document.querySelectorAll('#myTable td:first-child')].sort((a, b) => {
    const i = a.className.localeCompare(b.className);
    if (i == -1) a.parentNode.after(b);
    if (i == 1) a.parentNode.before(b);
    return i;
});


Niet getest! Zit op mobiel te typen
Dat geeft O(n log n) DOM permutaties. Het is wss. efficienter om het resulterende gesorteerde array na afloop O(n) lineair te doorlopen en op alle elementen appendChild te gebruiken om ze in de juiste volgorde te zetten.

Daarnaast verricht je daar een lexicale sortering en niet een numerieke.
Gezien het een tijdsdelta betreft, lijkt me dat er numeriek gesorteerd moet worden.

Dus:

JavaScript:
1
2
3
4
5
6
7
8
9
10
const data = [];
document.querySelectorAll( "#myTable td:first-child" ).forEach( element => {
  data.push({
    key : Number( element.className );
    row : element.parentNode
  });
});
data.sort(( first, second ) => first.key - second.key ).forEach(({ row }) => {
  row.parentNode.appendChild( row.parentNode )
});


Of als je een purist bent en echt wilt:

JavaScript:
1
2
3
4
5
6
7
8
9
[ ...document.querySelectorAll( "#myTable td:first-child" )]
  .map( element => ({
    key : Number( element.className );
    row : element.parentNode
  }))
  .sort(( first, second ) => first.key - second.key )
  .forEach(({ row }) => {
    row.parentNode.appendChild( row.parentNode );
  });


Kan relevant zijn, zeker voor grotere tables, want table-rendering is nou niet bepaald snel.

Belangrijk ook om row.parentNode te gebruiken, want het kan zijn dat de DOM-representatie van de tabel een tbody element tussen de table en tr elementen geschoven heeft gekregen.

Overigens: een classname is hier ook niet zo slim vanuit een ander oogpunt. Classes mogen ondanks verruiming van de constraints in HTML5 vziw nog steeds niet beginnen met een cijfer, maar moeten volgens spec een eerste karakter uit de reeks [a-zA-Z] hebben. Dat het in browsers wel werkt, wil niet meteen zeggen dat het ook valide is.

[ Voor 25% gewijzigd door R4gnax op 12-12-2020 14:35 ]


Acties:
  • 0 Henk 'm!

  • DJMaze
  • Registratie: Juni 2002
  • Niet online
R4gnax schreef op zaterdag 12 december 2020 @ 14:28:
Dat geeft O(n log n) DOM permutaties. Het is wss. efficienter om het resulterende gesorteerde array na afloop O(n) lineair te doorlopen
Hangt van het gebruikte sorteer algoritme af van de javascript engine.
Jij hebt het over quicksort (de positieve versie, maar kan langzamer zijn), maar insertsort en mergesort worden ook door engines gebruikt.

Als het goed is rendert de browser pas bij het volgende frame zodra de sort klaar is.
Meten is weten...

classname is idd sowieso een onhandige keuze. En tbody mist idd ook.

[ Voor 5% gewijzigd door DJMaze op 12-12-2020 14:49 ]

Maak je niet druk, dat doet de compressor maar


Acties:
  • 0 Henk 'm!

  • R4gnax
  • Registratie: Maart 2009
  • Laatst online: 06-09 17:51
DJMaze schreef op zaterdag 12 december 2020 @ 14:47:
Hangt van het gebruikte sorteer algoritme af van de javascript engine.
Jij hebt het over quicksort (de positieve versie, maar kan langzamer zijn), maar insertsort en mergesort worden ook door engines gebruikt.
Een general-purpose sorteeralgoritme heeft een n log n bound, worst case.
Je kunt discussies voeren over average case, dat wel.

In een klein aantal gevallen zal het meteen swappen tijdens de sorteer operatie tot minder mutaties leiden.
Zelf zou ik liever op zeker spelen en daar een gegarandeerde lineaire tijd pakken.

Als je echt wilt kun je het natuurlijk zo complex maken als je wilt, maar dan ga je richting het opbouwen v/e minimale diff tussen de ongesorteerde en gesorteerde lijst. En dat is waarschijnlijk voor dit geisoleerde geval nog vee---l minder efficient. :+

Acties:
  • 0 Henk 'm!

  • DJMaze
  • Registratie: Juni 2002
  • Niet online

Maak je niet druk, dat doet de compressor maar


Acties:
  • 0 Henk 'm!

  • Niekleair
  • Registratie: Oktober 2006
  • Laatst online: 11-06-2024
In de eerste plaats, allemaal hartelijk bedankt voor het medenken. _/-\o_

Wat achtergrond informatie; mijn werkgever heeft te kampen gehad met een ransomware aanval. Deze is in een vroeg stadium ontdekt; maar uit voorzorg is het hele netwerk platgelegd en wordt dit stap voor stap gescrubbed en weer opgebouwd.

Omdat ik mijn normale werkzaamheden niet kon uitvoeren, ben ik mij gaan verdiepen in scripting. Er zijn wat taken we graag verder willen automatiseren; maar we kwamen er nooit aan toe om dat te doen.

Ik heb met behulp van Python een script in elkaar gebakken dat een XML bestand parsed (met LXML) en daar informatie uit haalt en in een HTML tabel stopt. Dit script werkt; maar uiteraard kan het allemaal beter en efficienter omdat het door een beginner in elkaar geknutseld is.

Zo wil ik fast_iter toepassen in plaats van een lxml.etree in te laden om performance ten goede te komen. En het sorteren van de output; in plaats van het eindresultaat met Java sorteren is ook zo'n ding dat ik hoop toe te voegen.
Daos schreef op zaterdag 12 december 2020 @ 11:17:
Kan je trouwens niet al sorteren op je server? Dus dat je een gesorteerde tabel genereert? Lijkt mij mooier dan rommelen met javascript.
Het punt is dat de tabel wordt opgebouwd uit een XML bestand welke ik aangeleverd krijg. Ik heb geen invloed op hoe het XML bestand wordt opgebouwd, als ik het bestand eenmaal heb kan ik deze wel muteren.

Het XML heeft een child element per 'event'. Vervolgens heeft een event tot wel 1000 subchildren die allemaal een klein stapje voor het event bevatten.

Heel simpel gezegd (dit is een voorbeeld, dus dat de namen niet helemaal logisch zijn.. sorry >:) :
Het kan best zijn dat ik foutjes gemaakt heb in onderstaande XML code..

XML:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
<OBJECT>
  <EVENT>
    <PHASE NM="startUp" ID="1">
      <ED NM="eventDescription" CNT="Zwemfeestje" />
      <ET NM="entryTime">14400</ET>
      <ET NM="stepEnd">14403</ET>
      <EL NM="location">Central Hallway</EL>
      <EN NM="nextPhase" ID="2" />
    </PHASE>
    <PHASE NM="startUp" ID="2">
      <ED NM="eventDescription" CNT="Zwemfeestje" />
      <EP NM="previousPhase" ID="1" />
      <ET NM="entryTime">14403</ET>
      <ET NM="stepEnd">14408</ET>
      <EL NM="location">Central Hallway</EL>
      <EN NM="nextPhase" ID="3" />
    </PHASE>
<!-- gaat zo een tijdje door -->
    <PHASE NM="inOperation" ID="144">
      <ED NM="eventDescription" CNT="Zwemfeestje" />
      <EP NM="previousPhase" ID="143" />
      <ET NM="entryTime">17360</ET>
      <ET NM="stepEnd">17482</ET>
      <EL NM="location">Swimming Pool</EL>
      <EN NM="nextPhase" ID="145" />
    </PHASE>
<!-- enzovoort -->
    <PHASE NM="inOperation" ID="1920">
      <ED NM="eventDescription" CNT="Zwemfeestje" />
      <EP NM="previousPhase" ID="1919" />
      <ET NM="entryTime">74111</ET>
      <ET NM="stepEnd">75380</ET>
      <EL NM="location">Swimming pool</EL>
      <EN NM="nextPhase" ID="1921" />
    </PHASE>
    <PHASE NM="shutDown" ID="1921">
      <ED NM="eventDescription" CNT="Zwemfeestje" />
      <EP NM="previousPhase" ID="1920" />
      <ET NM="entryTime">75380</ET>
      <ET NM="stepEnd">75388</ET>
      <EL NM="location">Dressing Room</EL>
      <EN NM="nextPhase" ID="1922" />
    </PHASE>
<!-- enzovoort -->
    <PHASE NM="shutDown" ID="1983">
      <ED NM="eventDescription" CNT="Zwemfeestje" />
      <EP NM="previousPhase" ID="1982" />
      <ET NM="entryTime">77112</ET>
      <ET NM="stepEnd">77183</ET>
      <EL NM="location">Central Hallway</EL>
    </PHASE>
  </EVENT>
  <EVENT>
    <PHASE NM="startUp" ID="1984">
      <ED NM="eventDescription" CNT="Observatie" />
      <ET NM="entryTime">14520</ET>
      <ET NM="stepEnd">14532</ET>
      <EL NM="location">Central Hallway</EL>
      <EN NM="nextPhase" ID="1985" />
    </PHASE>
<!-- enzovoort -->


In dit voorbeeld bestaat een event uit 3 delen:
Opstartfase, actieve fase en afsluitfase. De naamgeving voor de fases is consequent "startUp" "inOperation" en "shutDown".

Ik wil graag een tabel maken die gesorteerd is op het begin van de afsluitfase. De tijd moet voor mensen leesbaar zijn. (Dus HH:MM:SS)

Uiteraard is de tabel niet lineair. Voor ieder event heeft iedere fase een andere tijdsduur. Dus de volgorde van de evenementen is afhankelijk van welke fase je wilt bekijken.

Zoals het XML bestand wordt aangeleverd, staat het gerangschikt op het begin van de opstarttijd.
Dus een tabel dat de aanvangsttijden weergeeft is vrij makkelijk te maken. Ik heb een python script, het werkt momenteel op basis van LXML-parsing. Op dit moment met de Etree; dat betekend dat de tree in memory gezet wordt en is dus niet het meest efficient. Aangezien de bestanden niet meer dan 25MB zijn, is dat nu nog niet zo'n punt. Als ik wat meer bekend ben met Python, XML en Java kan ik naar snellere en betere iteratie/parser technieken kijken.
R4gnax schreef op zaterdag 12 december 2020 @ 14:28:
Overigens: een classname is hier ook niet zo slim vanuit een ander oogpunt. Classes mogen ondanks verruiming van de constraints in HTML5 vziw nog steeds niet beginnen met een cijfer, maar moeten volgens spec een eerste karakter uit de reeks [a-zA-Z] hebben. Dat het in browsers wel werkt, wil niet meteen zeggen dat het ook valide is.
Het is eenvoudig genoeg om een letter voor de class name te zetten. Dan krijg je b.v. A14400; A16320 of t14400; t16320; daarmee is het in ieder geval valide en de sortering blijft identiek zolang ze allemaal gewoon dezelfde letter krijgen toch?

Ik ga kijken of ik de manier die @R4gnax adviseerd kan toepassen. Op dit moment ziet mijn python code om de tijd kolom te vullen er zo uit:
Python:
1
htmlBuilderMuck.write('<td class="' + edpRawTime + '">' + edpShowTime + '</td>')

Voor python is het dus een string; maar java kan de output gewoon als numeriek behandelen als ik het goed begrepen heb.

overigens, moet ik de header van deze colom ook een class geven? of kan die leeg blijven?

[ Voor 9% gewijzigd door Niekleair op 12-12-2020 21:21 ]

[img]error.jpg[/img]


Acties:
  • 0 Henk 'm!

  • DJMaze
  • Registratie: Juni 2002
  • Niet online
@Niekleair je webbrowser snapt ook XML.
Je zou dus ook ipv html de XML direct aan de browser kunnen geven en CSS en JavaScript daarop uitvoeren.

Betekent wel dat je moet leren hoe dat moet ;)

Maak je niet druk, dat doet de compressor maar


Acties:
  • 0 Henk 'm!

  • R4gnax
  • Registratie: Maart 2009
  • Laatst online: 06-09 17:51
DJMaze schreef op zaterdag 12 december 2020 @ 22:00:
@Niekleair je webbrowser snapt ook XML.
Je zou dus ook ipv html de XML direct aan de browser kunnen geven en CSS en JavaScript daarop uitvoeren.

Betekent wel dat je moet leren hoe dat moet ;)
Alleen ... als je daar wilt gaan sorteren ... moet je XSLT gaan toepassen.
En dat valt bij mij in elk geval zo'n beetje in de categorie "friends don't let friends do [...]" :+
Pagina: 1