Replace
with:
but I can't test if multiple bans will removed at the same time OR will get some weird behavior, at least I got some on Undernet.
Anyway, there's a key difference in the way I loop vs. the way Spike's code loops. And no, is not about me using while and a foreach and him using two foreach loops cos it's basically the same thing.
The difference lays in:
Code: Select all
set b1 [lindex [split $banlist] 0]
set banlist [lreplace $banlist 0 0]
Let me explain. Let's say the channel banlist is a list of numbers: 1, 2, 3, 4, 5, 6, 7, 8, 9 and 10 (in my example will use from 1 to 5). Now, if we look at the code:
Code: Select all
foreach ban1 [chanbans $ch] {
set ban1 [lindex $ban1 0]
foreach ban2 [chanbans $ch] {
set ban2 [lindex $ban2 0]
if {$ban1 eq $ban2} { continue }
if {[matchaddr $ban1 $ban2]} {
lappend redundant $ban2
}
}
}
And simplify it to see what's going on:
Code: Select all
foreach a [split $bans] {
foreach b [split $bans] {
puts "$a vs $b"
}
}
the result will be:
Code: Select all
% foreach a [split $bans] { foreach b [split $bans] { puts "$a vs $b" } }
1 vs 1
1 vs 2
1 vs 3
1 vs 4
1 vs 5
2 vs 1
2 vs 2
2 vs 3
2 vs 4
2 vs 5
3 vs 1
3 vs 2
3 vs 3
3 vs 4
3 vs 5
4 vs 1
4 vs 2
4 vs 3
4 vs 4
4 vs 5
5 vs 1
5 vs 2
5 vs 3
5 vs 4
5 vs 5
meaning
25 attempts to match one ban mask with another. With just a single lines inside the first loop that will basically remove the first element from the list every time the loop executes:
Code: Select all
foreach a [split $bans] {
set bans [lreplace $bans 0 0]
foreach b [split $bans] {
puts "$a vs $b"
}
}
the result will be:
Code: Select all
% foreach a [split $bans] { set bans [lreplace $bans 0 0]; foreach b [split $bans] { puts "$a vs $b" } }
1 vs 2
1 vs 3
1 vs 4
1 vs 5
2 vs 3
2 vs 4
2 vs 5
3 vs 4
3 vs 5
4 vs 5
meaning
10 attempts to match one ban mask with another. That's 15 matches that have been already done, meaning a 60% decrease in time used for matching bans.
If where to compare 30 bans then this means
900 attempts vs.
435 attempts ONLY by adding that
lreplace line.
Code: Select all
% set bans [list 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]
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
% set c 0
0
% foreach a [split $bans] { foreach b [split $bans] { incr c } }; puts $c
900
vs.
Code: Select all
% set bans [list 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]
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
% set c 0
0
% foreach a [split $bans] { set bans [lreplace $bans 0 0]; foreach b [split $bans] { incr c } }; puts $c
435
This means an 51.66% less matching. If where to compare 50 vs. same 50 then there would be
2500 matches vs.
1225 with just a single
lreplace line. That's INSANE!
I just noticed that I forgot to take that
if {$ban1 eq $ban2} { continue } line into account, but this doesn't make much of a difference, basically with 10 bans instead of 100 will do only 90 matches, still double of the other method that has the
lreplace trick in.
I think we can push this a notch further by adding another lreplace, but need to do some testing first.
Once the game is over, the king and the pawn go back in the same box.