Ldiff

From Base de connaissances eggdrops & TCL
Revision as of 08:42, 21 October 2020 by CrazyCat (talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search
Attention.png Ceci ne fait pas partie du langage tcl, c'est une fonction utile personnelle

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]}}]
}

Voir aussi