Ldiff
Contents
Description
Cette fonction compare deux listes et retourne une liste qui contient tous les éléments de la première liste qui ne sont pas dans la seconde.
Utilisation
Code de la fonction
proc ldiff {list1 list2} {
foreach suppr $list2 {
set ind [lsearch $list1 $suppr]
set list1 [lreplace $list1 $ind $ind]
}
return $list1
}
Alternative
MenzAgitat a fait une version légèrement différente de la procédure:
proc ldiff {list1 list2} {
foreach element $list1 {
if { !($element in $list2) } {
lappend diff $element
}
}
return $diff
}
Elle semble légèrement plus rapide que la mienne.
Version avec lmap
proc ldiff {list1 list2 {option -exact}} {
if {$option ne "-nocase"} { set option -exact }
return [lmap x $list1 {expr {[lsearch $option $list2 $x] < 0 ? $x : [continue]}}]
}
Exemple d'utilisation
Voici un exemple très parlant: le but est d'avoir la liste des utilisateurs présents sur un canal mais n'étant pas des utilisateurs spéciaux (par exemple les robots).
# $bots contient les nicks des robots présents sur le canal
set bots { $::botnick "BotStat" "Denora" }
# users est la liste des utilisateurs présents sur $chan
set users [chanlist $chan]
# $humans est la liste des "humains"
set humans [ldiff $users $bots]
Un peu plus loin
Comme évoqué dans A propos des listes, les caractères spéciaux peuvent poser des soucis. Pour remédier à celà, j'utilise une version légèrement différente de cette fonction qui fait appel à un nettoyage des données à comparer:
proc ldiff {list1 list2} {
foreach suppr $list2 {
set ind [lsearch [filt $list1] [filt $suppr]]
set list1 [lreplace $list1 $ind $ind]
}
return list1
}
proc filt {data} {
regsub -all -- \\\\ $data \\\\\\\\ data
regsub -all -- \\\[ $data \\\\\[ data
regsub -all -- \\\] $data \\\\\] data
regsub -all -- \\\} $data \\\\\} data
regsub -all -- \\\{ $data \\\\\{ data
regsub -all -- \\\" $data \\\\\" data
return $data
}
Autre filtrage
MenzAgitat a proposé une autre fonction de filtrage qui semble bien plus simple :
proc filt {data} {
return [regsub -all {\W} $data {\\&}]
}
Ce n'est pas testé mais comme je lui fais confiance en TCL, je diffuse.
Fonction inverse: lintersect
Pour extraire les éléments de list1 qui sont aussi présents dans list2:
proc lintersect {list1 list2 {option -exact}} {
if {$option ne "-nocase"} { set option -exact }
return [lmap x $list1 {expr {[lsearch $option $list2 $x] >= 0 ? $x : [continue]}}]
}