How to compare condition with multiple values in TCL - tcl

I am trying to compare using if condition
xorg != "t8405" or "t9405" or "t7805" or "t8605" or "t8705"
I want to compare if xorg is not equal to all of these values on the right side then perform Y.
I am trying to figure out how can I have more smart comparison better or shell I compare xorg with one by one value?
Regards

I think the in and ni (not in) operators are what you should look at. They test for membership (or non-membership) of a list. In this case:
if {$xorg ni {"t8405" "t9405" "t7805" "t8605" "t8705"}} {
puts "it wasn't in there!"
}
If you've got a lot of these things and are testing frequently, you're actually better off putting the values into the keys of an array and using info exists:
foreach key {"t8405" "t9405" "t7805" "t8605" "t8705"} {
set ary($key) 1
}
if {![info exists ary($xorg)]} {
puts "it wasn't in there!"
}
It takes more setup doing it this way, but it's actually faster per test after that (especially from 8.5 onwards). The speedup is because arrays are internally implemented using fast hash tables; hash lookups are quicker than linear table scans. You can also use dictionaries (approximately dict set instead of set and dict exists instead of info exists) but the speed is similar.
The final option is to use lsearch -sorted if you put that list of things in order, since that switches from linear scanning to binary search. This can also be very quick and has potentially no setup cost (if you store the list sorted in the first place) but it's the option that is least clear in my experience. (The in operator uses a very simplified lsearch internally, but just in linear-scanning mode.)
# Note; I've pre-sorted this list
set items {"t7805" "t8405" "t8605" "t8705" "t9405"}
if {[lsearch -sorted -exact $items $xorg] < 0} {
puts "it wasn't in there!"
}
I usually use either the membership operators (because they're easy) or info exists if I've got a convenient set of array keys. I often have the latter around in practice...

Related

How to create multidimensional hash like structure

What is the best way to create and access multidimensional hashes in TCL that are present in perl for example:
if{ $line = (\D+) ....} {
$hash{name}=$1
$hash{height}=$2
}
etc
You can either use composite keys like this (the neatest option in the simplest cases):
set x 1
set y 2
set d($x,$y) 3
Or you can put a dictionary in an array element:
set x 1
set y 2
dict set d($x) $y 3
Or you can use a nested dictionary:
set x 1
set y 2
dict set d $x $y 3
There are some subtleties about the differences between them, but most of the time most people's code doesn't really care and doesn't need to care.
Here's the case where you are most likely to need to care. If you're doing the first option and you can't make guarantees about what characters might be in the atomic keys, you can use list to build the overall key (as that knows how to apply quoting rules to avoid confusion):
set x "the quick, cunning brown fox"
set y "the ever-so, ever-so lazy dog"
set d([list $x $y]) "jumps over"
Of course, that makes access more awkward as you need to use list (or another list-building command) when building the keys (or have the right string literals, which is annoying for larger keys). The other two options have no problems at all with confusing arbitrary keys; dictionaries had not getting mixed up over such things as an explicit design goal.

rails - how much faster are number comparisons vs text comparisons

I have a pretty expensive method in my model that compares text items of arrays for many many items.
It runs really slow. If I use a relational database table and compare the ID's only, will my method run a lot faster?
/EDIT
I'm attempting to benchmark the below:
#matches = #location_matches.sort do |l1, l2|
l1.compute_score(current_user) <=> l2.compute_score(current_user)
end
#matches.reverse!
To be short, I guess number comparison will be faster because comparing string is about comparing character after character (advice: in Ruby use symbols when you can, their comparison is much faster).
Whatever, you'll find there, everything you need to benchmark and get your detailled results.
A code sample:
require 'benchmark'
n = 50000
Benchmark.bm do |x|
x.report("for:") { for i in 1..n; a = "1"; end }
x.report("times:") { n.times do ; a = "1"; end }
x.report("upto:") { 1.upto(n) do ; a = "1"; end }
end
The result:
user system total real
for: 1.050000 0.000000 1.050000 ( 0.503462)
times: 1.533333 0.016667 1.550000 ( 0.735473)
upto: 1.500000 0.016667 1.516667 ( 0.711239)
Your first task is to replace that sort with a sort_by, you can also skip the reverse! by sorting things in the desired order in the first place:
#matches = #location_matches.sort_by { |loc| -loc.compute_score(current_user) }
The sort method will have to do many comparisons while sorting and each comparison requires two compute_score calls, the sort_by method does a Schwartzian Transform internally so your expensive compute_score will only be called once per entry. The negation inside the block is just an easy way to reverse the sort order (I'm assuming that your scores are numeric).
Fix up the obvious performance problem and then move on to benchmarking various solutions (but be sure to benchmark sort versus sort_by just to be sure that "obvious" matches reality).

TCL - return variable vs upvar and modify

Would like to take an advice from TCL professionals for best practice.
Say you want to construct a list with a specific data by using a proc. Now which is the best way?
proc processList { myList } {
upvar $myList list_
#append necessary data into list_
}
proc returnList {} {
set list_ {}
#append necessary data into list_
return $list_
}
set list1 {}
processList list1
set list2 [returnList ]
Which one of this practices is recommended?
EDIT: I am sorry but I can't understand consensus (and explanation) of people who answered to this question.
I virtually always use the second method:
proc returnList {} {
set result {}
# ... accumulate the result like this ...
lappend result a b c d e
return $result
}
set lst [returnList]
There's virtually no difference in memory usage or speed, but I find it easier to think functionally. Also, in Tcl 8.5 you can do the splitting up of the result list relatively simply (if that's what you need):
set remainderList [lassign [returnList] firstValue secondValue]
With that, you'd end up with a in $firstValue, b in secondValue, and c d e in $remainderList.
The first option modify an existing list whereas the second create a new list. For a better comparison, I would add a parameter to returnList() and create a return value from that parameter.
Given that, the difference is in the way of passing parameters -- by reference or by value-- and in the memory budget needed by each operation.
There is no side effect with the second method, but it could be very consuming if the list is huge.
There is no general rule for recommending one over the other. My own rule is to start with the second way unless other constraints lead not to do so.
What would the syntax be for the equivalent of:
set lst [returnList]
If you wanted to return more than one list at once?
I thought that if you did something like this:
return [$list1 $list2]
It was supposed to return a list of lists, which you could then access with lindex. But, that doesn't appear to be exactly what it does. It really just gives you two lists back, without external curly braces grouping them into a single list. In Perl, you can do something like:
($var1, $var2) = process_that_returns_two_values;
But I don't think "set" allows that in Tcl.

Tcl and records (structs)

Package struct::record from TCLLIB provides means for emulating record types. But record instances are commands in the current namespace and not variables in the current scope. This means there is no garbage collection for record instances. Passing name of the record instance to a procedure means passing it by reference not by value, it is possible to pass string representation of the record as parameter but it requires to create another instance in the procedure, configure it and delete by hand, it's annoying. I wonder about the rationale behind this design. A simple alternative is provide a lisp-style records - a set of construction, access and modification procedures and represent records as lists.
The struct::record implementation is, from my viewpoint, an oo-style implementation. If you're searching for a data-style implementation (like lisp) where the commands are totally separate from the data, you might want to look at the dict command.
I'll note that oo-style and data-style are really not good descriptions, but they were the best I could think of offhand.
You most certainly can do it “the Lisp way”.
proc mkFooBarRecord {foo bar} {
# Keep index #0 for a "type" for easier debugging
return [list "fooBarRecord" $foo $bar]
}
proc getFoo {fooBarRecord} {
if {[lindex $fooBarRecord 0] ne "fooBarRecord"} {error "not fooBarRecord"}
return [lindex $fooBarRecord 1]
}
# Etc.
That works quite well. (Write it in C and you can make it more efficient too.) Mind you, as a generic data structure, it seems that many people prefer Tcl 8.5's dictionaries. There are many ways to use them; here's one:
proc mkFooBarRecord {foo bar} {
return [dict create "type" fooBarRecord "foo" $foo "bar" $bar]
}
proc getFoo {fooBarRecord} {
dict with fooBarRecord {
if {$type ne "fooBarRecord"} {error "not fooBarRecord"}
return $foo
}
}
As for the whole structures versus objects debate, Tcl tends to regard objects as state with operations (leading to a natural presentation as a command, a fairly heavyweight concept) whereas structures are pure values (and so lightweight). Having written a fair chunk on this, I really don't know what's best in general; I work on a case-by-case basis. If you are going with “structures”, also consider whether you should have collections that represent fields across many structures (equivalent to using column-wise storage instead of row-wise storage in a database) as that can lead to more efficient handling in some cases.
Also consider using a database; SQLite integrates extremely well with Tcl, is reasonably efficient, and supports in-memory databases if you don't want to futz around with disk files.
I will not answer your question, because I was not been using Tcl for many years and I never use this kind of struct, but I can give you the path to two possible places that are very plausible to provide a good answer for you:
The Tcl'ers Wiki http://wiki.tcl.tk
The Frenode's Tcl IRC channel
At the time I used Tcl they proved to be invaluable resources.

Predictable order of response to Tcl array names?

I know that the names returned by [array names X] are in an undefined order, but are they always in the same undefined order?
I'm going through a very large array, and would like to log progress to a file in case of a crash, so I can resume part-way through again.
PS. A quick experiment implies it is always the same 'random' order, but this doesn't mean it's true!
The short answer is that you can't rely on the order and your best bet is to [lsort [array names X]] and use that order.
The long answer is that the order should be stable as long as the keys are the same (and its the same Tcl version)... but I still wouldn't rely on it.
If you're using Tcl 8.5 or later, you might want to look at using a Dict instead of an array. The order of elements for a Dict is the order they were added in.