Check whether procedure return list or list with sub list - tcl

I am facing problem how to check whether the list returned by the procedure consist of a single list or may have sub list inside.
#simple list
set a { 1 2 3 4}
# list consisting of sub list
set a { {1 2 3 4} {5 6 7 7} }
As above some times the variable a will have a list and sometime proc will return list consisting of sub list.
Update part
set a [mysqlsel $db "SELECT * FROM abc" -list]
I do not know weather query will return a single list or list consisting of sublist

You should really rethink your approach: since Tcl is typeless, you can't really tell if {{1 2 3 4} {5 6 7 8}} is a list of two lists or a list of two strings or a literal string {1 2 3 4} {5 6 7 8}, because all these propositions are true depending on how you make Tcl interpret this value.
Another thing, is that even if you were to try something like catch {lindex $element 0} or string is list $element on each top-level element to see if it can be interpreted as a list, that would qualify as being non-lists only strings that really can't be parsed as lists, like aaa { bbb. And string foo is also a proper list (of length 1, containing "foo" as its sole element).
One approach you can consider using is wrapping the returned value in another value which has some sort of "tag" attached to it--the trick routinely used in some other typeless languages like LISP and Erlang. That would look like this:
If you need to return 1 2 3 4, return {flat {1 2 3 4}} instead.
If you need to return {1 2 3 4} {5 6 7 8}, return {nested {{1 2 3 4} {1 2 3 4 5}}}.
Then in the client code do switch on the "tag" element and decapsulate the payload:
lassign [your_procedure ...] tag payload
switch -- $tag {
flat {
# do something with $payload
}
nested {
# do something with $payload
}
}

Related

Getting number of duplicate elements in a list (in tcl)

I have a list which looks like
list = {ab bc 8 ab d1 10 xy uv bc ab xy 10 d1}
I would like to know how often each element of the list occurs inside it, that is, I need a result like this:
ab 3
bc 2
8 1
d1 2
....
I prefer a single line argument (if such exists) instead of a proc. I need to work with both: list elements and their frequency in the list.
Any advice is welcome.
Thank you!
Assuming that counter is the name of the dictionary where you want to collect this information (and is either currently unset or set to the empty string):
foreach item $list {dict incr counter $item}
You can then print that out in approximately the form you gave with:
dict for {item count} $counter {puts [format "%6s %-3d" $item $count]}
Note that this second line is about displaying the data, not actually finding it out.

How to sort nested dictionaries in TCL

I have a nested dictionary in TCL where the values at a particular index are unsorted at a subindex value, for example in this dictionary, I want to sort 55,21,36 and move the subkeys while sorting, and I also want to sort 103,344,3 while moving around their subkeys as well
I am very confused how one goes about doing something like this. I cannot use lsort -index -stride since my sub Dictionary isn't a single flattened list
a1,a2 {0,6 {103 55} 1,5 {344 21} 6,7 {3 36}}
Expected Output 1 [Sort based on 21,36,55 [final subvalues], 55 goes all the way towards the end with its key]
a1,a2 {1,5 {344 21} 6,7 {3 36} 0,6 {103 55}}
Expected Output 2 [Sort based on 344,3,103, 344 goes all the way towards the end along with its key]
a1,a2 {6,7 {3 36} 0,6 {103 55} 1,5 {344 21}}

How to convert path data to adjacency list

I'm setting up a rails "import from csv" task, and I came across departments data (in db) in the form of path. I want it to be adjacency list.
Smth I have:
ID, NAME, PATH
---------
1,Valve,000
2,Steam,000.000
3,Sales,000.000.000
4,Developers,000.000.112
7,Designers,000.000.112.000
8,Game Designers,000.000.112.000.000
9,UI Designers,000.000.112.000.002
10,Web Designers,000.000.112.000.001
11,3D Designers,000.000.112.000.003
12,Accounting managers,000.000.114.000
13,Accounting topmanagers,000.000.114.000.000
Smth I want:
ID, NAME, PATH, PARENT_ID
---------
1,Valve,000, nil
2,Steam,000.000, 1
3,Sales,000.000.000, 2
4,Developers,000.000.112, 2
7,Designers,000.000.112.000, 4
8,Game Designers,000.000.112.000.000, 7
9,UI Designers,000.000.112.000.002, 7
10,Web Designers,000.000.112.000.001, 7
11,3D Designers,000.000.112.000.003, 7
12,Accounting managers,000.000.114.000, 322
13,Accounting topmanagers,000.000.114.000.000, 12
The string appears to describe a directed tree, except the accounting managers,
'12,Accounting managers,000.000.114.000'
seem to have no boss. I've therefore added
'14,Accounting big cheese,000.000.114'
Here's the data.
data =<<-_
ID, NAME, PATH
---------
1,Valve,000
2,Steam,000.000
3,Sales,000.000.000
4,Developers,000.000.112
7,Designers,000.000.112.000
8,Game Designers,000.000.112.000.000
9,UI Designers,000.000.112.000.002
10,Web Designers,000.000.112.000.001
11,3D Designers,000.000.112.000.003
14,Accounting big cheese,000.000.114
12,Accounting managers,000.000.114.000
13,Accounting topmanagers,000.000.114.000.000
_
We can use split("\n") to convert this string to an array of lines, and then determine the parentage of each node as follows.
r1, r2, *rest = data.split("\n")
str = [
r1,
r2,
rest.map do |s|
parent_match = s[/(?:\d{3}\.)*\d{3}(?=\.\d{3})/]
parent = arr.find { |ss| parent_match == ss[/(?:\d{3}\.)*\d{3}/] }
parent.nil? ? "#{s}, nil" : "#{s}, #{ parent[/\d+/] }"
end
].join("\n")
puts str
ID, NAME, PATH
---------
1,Valve,000, nil
2,Steam,000.000, 1
3,Sales,000.000.000, 2
4,Developers,000.000.112, 2
7,Designers,000.000.112.000, 4
8,Game Designers,000.000.112.000.000, 7
9,UI Designers,000.000.112.000.002, 7
10,Web Designers,000.000.112.000.001, 7
11,3D Designers,000.000.112.000.003, 7
14,Accounting big cheese,000.000.114, 2
12,Accounting managers,000.000.114.000, 14
13,Accounting topmanagers,000.000.114.000.000, 12
In map's block suppose
s = '8,Game Designers,000.000.112.000.000'
then
parent_match = s[/(?:\d{3}\.)*\d{3}(?=\.\d{3})/]
#=> "000.000.112.000"
parent_match is a string of all the triples of digits separated by periods in s, other than the last period followed by the last triple of digits. The regular expression reads, "match zero or more groups of 3 digits followed by a period, followed by 3 digits, provided this match is immediately followed by a period and 3 digits ((?=\.\d{3})) being a positive lookahead).
We then loop through rest looking for an element that ends with parent_match:
parent = rest.find { |ss| parent_match == ss[/(?:\d{3}\.)*\d{3}/] }
#=> "7,Designers,000.000.112.000"
The regex /(?:\d{3}\.)*\d{3}/ reads, "match zero or more groups of 3 digits followed by a period, followed by 3 digits".
In the next line:
parent.nil?
#=> false
so the block returns
"#{s}, #{ parent[/\d+/] }"
#=> "8,Game Designers,000.000.112.000.000, 7"
parent[/\d+/] merely extracts the digit character(s) at the beginning of parent.
Had I not added the line
14,Accounting big cheese,000.000.114
the following line ('12,Accounting ...') would have ended, ', nil'.

TCL to JSON : Writing JSON output using huddle in single line

Let us consider a tcl data as follows:
set arr {a {{c 1} {d {2 2 2} e 3}} b {{f 4 g 5}}}
Converted into Json format using huddle module:
set json_arr [huddle jsondump [huddle compile {dict * {list {dict d list}}} $arr]]
puts $json_arr
Json fromatted array:
{
"a": [
{"c": 1},
{
"d": [
2,
2,
2
],
"e": 3
}
],
"b": [{
"f": 4,
"g": 5
}]
}
Writing in a single line:
set json_arr [huddle jsondump [huddle compile {dict * {list {dict d list}}} $arr] {} {}]
puts $json_arr
Updated Json formatted array:
{"a":[{"c":1},{"d":[2,2,2],"e":3}],"b":[{"f":4,"g":5}]}
What is the meaning of {} {} here?
Can I use the same for single line in case of output by json and json::write module ?
The last three, optional, arguments to jsondump are offset, newline, and begin_offset. You can use those to specify strings that are to be used to format the output string. If you don’t specify them, default strings will be used.
If you do specify them, you need to follow the protocol for optional arguments, i.e. if you want to specify begin_offset, you need to specify offset and newline too, etc. In this case, offset and newline are specified to be empty strings, and begin_offset uses its default value.
Try invoking jsondump with dummy values to get an idea of how they are used:
% huddle jsondump [huddle compile {dict * {list {dict d list}}} $arr] <A> <B> <C>
{<B><C><A>"a": [<B><C><A><A>{"c": 1},<B><C><A><A>{<B><C><A><A><A>"d": [<B><C><A><A><A><A>2,<B><C><A><A><A><A>2,<B><C><A><A><A><A>2<B><C><A><A><A>],<B><C><A><A><A>"e": 3<B><C><A><A>}<B><C><A>],<B><C><A>"b": [{<B><C><A><A><A>"f": 4,<B><C><A><A><A>"g": 5<B><C><A><A>}]<B><C>}
A newline and a begin_offset string is inserted around each component, and one or more offset strings are inserted before a component to reflect the indentation level.
json::write uses the indented and aligned subcommands to customize formatting.

How to find intersection or subset of two CSV files

I have 2 CSV files containing two columns and a large number of rows. The first column is the id, and the second is the set of paired values.
e.g.:
CSV1:
1 {[1,2],[1,4],[5,6],[3,1]}
2 {[2,4] ,[6,3], [8,3]}
3 {[3,2], [5,2], [3,5]}
CSV2:
1 {[2,4] ,[6,3], [8,3]}
2 {[3,4] ,[3,3], [2,3]}
3 {[1,4],[5,6],[3,1],[5,5]}
Now I need to get a CSV file which contains either exact matching items or subset which belongs to both CSVs.
Here the result should be:
{[2,4] ,[6,3], [8,3]}
{[1,4],[5,6],[3,1]}
Can anyone suggest python code to do this?
As suggested by this answer you can use set.intersection to get the intersection of two sets, however this does not work with lists as items. Instead you can also use filter (comparable to this answer):
>>> l1 = [[1,2],[1,4],[5,6],[3,1]]
>>> l2 = [[1,4],[5,6],[3,1],[5,5]]
>>> filter(lambda q: q in l2, l1)
[[1, 4], [5, 6], [3, 1]]
In Python 3 you should convert it to list since there filter returns an iterable:
>>> list(filter(lambda x: x in l2,l1))
You can load CSV files (if they are really comma [or some other character] separated files) with csv.reader or pandas.read_csv for example.