I've tried looking all over the place and haven't found a good answer for this. I'm trying to write nested foreach loops in tcl that read lines from two different text files. The inner foreach loop will run completely through but the outer foreach loop will break after just evaluating the first line in the file. The text files look something like this (except much larger).
input1.txt:
1
2
3
4
5
6
7
8
9
10
input2.txt:
a
b
c
d
e
f
g
h
i
j
and my nested foreach loops are constructed like this:
# Open file 1;
set FID1 [open input1.txt r];
# Open file 2
set FID2 [open input2.txt r];
# Open an output file to check the foreach loops;
set outFID [open outputcheck.txt w];
# Nest the foreach loops to read both files
foreach PropLine [split [read $FID1] \n] {
foreach GMprop [split [read $FID2] \n] {
puts $outFID "$PropLine $GMprop";
}
}
close $FID1;
close $FID2;
close $outFID;
and my outputcheck.txt file contains
1 a
1 b
1 c
1 d
1 e
1 f
1 g
1 h
1 i
1 j
I am running this code through the OpenSEES.exe executable on a PC with Windows 7 operating system.
Thanks in advance for any insight.
If you want to do something with file2 for every line of file1, then
foreach PropLine [split [read $FID1] \n] {
foreach GMprop [split [read $FID2] \n] {
puts $outFID "$PropLine $GMprop";
}
# jump back to the start of the file, so you can re-read it
# for the next iteration of the outer foreach loop
seek $FID2 0 start
}
But, it just looks like you want to pair the lines, so
foreach PropLine [split [read -nonewline $FID1] \n] \
GMprop [split [read -nonewline $FID2] \n] \
{
puts $outFID "$PropLine $GMprop";
}
Tcl lets you iterate over multiple lists simultaneously, very handy: http://tcl.tk/man/tcl8.6/TclCmd/foreach.htm
Although I'd be tempted to read the files line-by-line:
while {true} {
set status1 [gets $FID1 PropLine]
set status2 [gets $FID2 GMprop]
if {$status1 == -1 && $status2 == -1} break
puts $outFID "$PropLine $GMprop"
}
Related
I'm teaching myself Lua by reading Ierusalimschy's Programming in Lua (4th edition), and doing the exercises. Exercise 6.5 is
Write a function that takes an array and prints all combinations of the elements in the array.
After this succinct statement the book gives a hint that makes it clear that what one is expected to do is to write a function that prints all the C(n, m) combinations of m elements from an array of n elements.
I implemented the combinations function shown below:
function combinations (array, m)
local append = function (array, item)
local copy = {table.unpack(array)}
copy[#copy + 1] = item
return copy
end
local _combinations
_combinations = function (array, m, prefix)
local n = #array
if n < m then
return
elseif m == 0 then
print(table.unpack(prefix))
return
else
local deleted = {table.unpack(array, 2, #array)}
_combinations(deleted, m - 1, append(prefix, array[1]))
_combinations(deleted, m, prefix)
end
end
_combinations(array, m, {})
end
It works OK, but it is not tail-recursive.
Can someone show me a tail-recursive function that does the same thing as combinations above does?
(For what it's worth, I am using Lua 5.3.)
NB: I realize that the exercise does not require that the function be tail-recursive. This is a requirement I have added myself, out of curiosity.
EDIT: I simplified the function slightly, but removing a couple of nested functions that were not adding much.
There is a third option, one that doesn't have a snake eating it's tail. Although recursion with tail-calls don't lead to stack overflow, I avoid doing so out of personal preference. I use a while loop and a stack that holds the information for each iteration. Within the loop you pop the next task from the stack, do the work, then push next task onto the stack. I feel it looks cleaner and it's easier to visualize the nesting.
Here is how I would translate your code into the way I would write it:
function combinations(sequence, item)
local function append(array, item)
local copy = {table.unpack(array)}
copy[#copy + 1] = item
return copy
end
local stack = {}
local node = { sequence, item, {} }
while true do
local seq = node[ 1 ]
local itm = node[ 2 ]
local pre = node[ 3 ]
local n = #seq
if itm == 0 then
print(table.unpack(pre))
elseif n < itm then
-- do nothing
else
local reserve = {table.unpack(seq, 2, #seq)}
table.insert(stack, { reserve, itm, pre })
table.insert(stack, { reserve, itm-1, append(pre, seq[ 1 ]) })
end
if #stack > 0 then
node = stack[ #stack ] -- LIFO
stack[ #stack ] = nil
else
break
end
end
end
You can use this while-loop stack/node technique for just about any recursive method. Here is an example where it's applied to printing deeply nested tables: https://stackoverflow.com/a/42062321/5113346
My version, using your input example gives the same output:
1 2 3
1 2 4
1 2 5
1 3 4
1 3 5
1 4 5
2 3 4
2 3 5
2 4 5
3 4 5.
Forgive me if it doesn't work with other passed params because I didn't try to solve the answer to the exercise but rather just rewrite the code in your original post.
OK, I think I found one way to do this:
function combinations (array, m)
local dropfirst = function (array)
return {table.unpack(array, 2, #array)}
end
local append = function (array, item)
local copy = {table.unpack(array)}
copy[#copy + 1] = item
return copy
end
local _combinations
_combinations = function (sequence, m, prefix, queue)
local n = #sequence
local newqueue
if n >= m then
if m == 0 then
print(table.unpack(prefix))
else
local deleted = dropfirst(sequence)
if n > m then
newqueue = append(queue, {deleted, m, prefix})
else
newqueue = queue
end
return _combinations(deleted, m - 1,
append(prefix, sequence[1]),
newqueue)
end
end
if #queue > 0 then
newqueue = dropfirst(queue)
local newargs = append(queue[1], newqueue)
return _combinations(table.unpack(newargs))
end
end
_combinations(sequence, m, {}, {})
end
This version is, I think, tail-recursive. Unfortunately, it does not print out the results in as nice an order as did my original non-tail-recursive version (not to mention the added complexity of the code), but one can't have everything!
EDIT: Well, no, one can have everything! The version below is tail-recursive, and prints its results in the same order as does the original non-tail-recursive version:
function combinations (sequence, m, prefix, stack)
prefix, stack = prefix or {}, stack or {}
local n = #sequence
if n < m then return end
local newargs, newstack
if m == 0 then
print(table.unpack(prefix))
if #stack == 0 then return end
newstack = droplast(stack)
newargs = append(stack[#stack], newstack)
else
local deleted = dropfirst(sequence)
if n > m then
newstack = append(stack, {deleted, m, prefix})
else
newstack = stack
end
local newprefix = append(prefix, sequence[1])
newargs = {deleted, m - 1, newprefix, newstack}
end
return combinations(table.unpack(newargs)) -- tail call
end
It uses the following auxiliary functions:
function append (sequence, item)
local copy = {table.unpack(sequence)}
copy[#copy + 1] = item
return copy
end
function dropfirst (sequence)
return {table.unpack(sequence, 2, #sequence)}
end
function droplast (sequence)
return {table.unpack(sequence, 1, #sequence - 1)}
end
Example:
> combinations({1, 2, 3, 4, 5}, 3)
1 2 3
1 2 4
1 2 5
1 3 4
1 3 5
1 4 5
2 3 4
2 3 5
2 4 5
3 4 5
Ironically, this version achieves tail-recursion by implementing its own stack, so I am not sure it is ultimately any better than the non-tail-recursive version... Then again, I guess the function's stack actually lives in the heap (right?), because Lua's tables are passed around by reference (right?), so maybe this is an improvement, after all. (Please correct me if I'm wrong!)
How can I mix two variables with different lengths in a third variable?
Variable1 has 48 entries, variable2 has 16 entries. Variable3 should have after every third line from variable 1 the entries from variable two in every fourth line.
The length of the two variables could be different, but is always divisible by 3.
$i = 0 ; $var3 = $var1 | % { "$_ $($var2[$i])"; $i++ }
Doesn't work, because it is for variables of the same length
Example:
$Var1 (48 entries)
Name1
Location1
Country1
Name2
Location2
Country2
.
.
Name16
Location16
Country16
$Var2 (16 entries)
Date1
Date2
.
.
Date16
$Var3 (should have 64 entries)
Name1
Location1
Country1
Date1
.
.
Name16
Location16
Country16
Date16
I'm assuming $var1 and $var2 are arrays, and the "entries" are each elements.
If I had to use the method you're using to store variables, I'd do it like this:
$var1 = #('Name1','Location1','Country1','Name2','Location2','Country2','Name3','Location3',
'Country3','Name4','Location4','Country4','Name5','Location5','Country5','Name6','Location6',
'Country6','Name7','Location7','Country7','Name8','Location8','Country8','Name9','Location9',
'Country9','Name10','Location10','Country10','Name11','Location11','Country11','Name12',
'Location12','Country12','Name13','Location13','Country13','Name14','Location14','Country14',
'Name15','Location15','Country15','Name16','Location16','Country16');
$var2 = #('Date1','Date2','Date3','Date4','Date5','Date6','Date7','Date8','Date9','Date10',
'Date11','Date12','Date13','Date14','Date15','Date16');
$var3 = #();
for ($i = 0; $i -lt $var2.Count; $i++) {
$var3 += $var1[$i * 3];
$var3 += $var1[($i * 3) + 1];
$var3 += $var1[($i * 3) + 2];
$var3 += $var2[$i];
}
In reality, I'd probably store this as an array of hashtables, or in a PSObject/PSCustomObject as tuples. Hell, I might even prefer building a DataTable to a flat array.
I'm trying to join three text files in similar formats based on common fields, while keeping the uncommon fields. Here's an example:
File1:
X
A 1
B 3
C 2
D 1
File2:
Y
A 3
C 2
E 3
File3:
Z
A 2
E 1
D 1
F 3
Merged:
X Y Z
A 1 3 2
B 3 - -
C 2 2 -
D 1 - 1
E - 3 1
F - - 3
It doesn't have to be a - where there's no corresponding value. The join command in this question https://unix.stackexchange.com/questions/43417/join-two-files-with-matching-columns works well except that it doesn't keep the uncommon fields.
Thank you.
join can't do what you're asking for, but here's a Python program that does:
#!/usr/bin/env python
import sys
files = map(open, sys.argv[1:]) # list of input files
headers = map(file.readline, files) # list of strings
headers = map(str.strip, headers)
blanks = ['-'] * len(headers)
data = {} # { rowname : [datum...] }
for ii, infile in enumerate(files): # read each file
for line in infile:
key, value = line.split()
if key not in data:
data[key] = blanks[:] # deep copy
data[key][ii] = value
print '\t', '\t'.join(headers)
for key, values in sorted(data.iteritems()):
print key, '\t', '\t'.join(values)
I have two list:
set lista {5 6}
set listb {8 9}
and the following code is used to loop the two lists:
foreach listaelement listbelement $lista $listb {
puts $listaelement &listbelement
}
how can we use foreach to achieve the output is:
first element from lista, first element from listb,
first element from lista, second element from listb,
second element from lista, first element from listb,
second element from lista, second element from listb,
5 8
5 9
6 8
6 9
Just nesting the loops and using -nonewline should give the output you desire:
foreach listelementa $lista {
foreach listelementb $listb {
puts -nonewline "$listelementa $listelementb "
}
}
puts ""
NB: You need to use quotes in the puts statement to stop Tcl interpreting the first argument as a channel id.
Tcl does allow you to reference multiple lists in a foreach statement
foreach listelementa $lista listelementb $listb {
puts -nonewline "$listelementa $listelementb "
}
puts ""
However this gives 5 8 6 9 as its output - not what you require.
Edit: I'm pretty sure when I answered the question that the output was formatted as 1 line, if you actually want 1 line for each pair then you don't need the -nonewline on the puts and the trailing spaces and final puts can also go.
set lista {5 6}
set listb {8 9}
set indexb [expr ([llength $listb ] -1)]
foreach listano $lista {
for {set i 0 } {$i <= $indexb } {incr i} {
set element [lindex $listb $i]
puts "element is $listano $element"
}
}
element is 5 8
element is 5 9
element is 6 8
element is 6 9
I have a text file which has hex values, one value on one separate line. A file has many such values one below another. I need to do some analysis of the values for which i need to but some kind of delimiter/marker say a '#' in this file before line numbers 32,47,62,77... difference between two line numbers in this patterin is 15 always.
I am trying to do it using awk. I tried few things but didnt work.
What is the command in awk to do it?
Any other solution involving some other language/script/tool is also welcome.
Thank you.
-AD
This is how you can use AWK for it,
awk 'BEGIN{ i=0; } \
{if (FNR<31) {print $0} \
else {i++; if (i%15) {print $0} else {printf "#%s\n",$0}}\
}' inputfile.txt > outputfile.txt
How it works,
BEGIN sets an iterator for counting from your starting line 32
FNR<31 starts counting from the 31st record (the next record needs a #)
input lines are called records and FNR is an AWK variable that counts them
Once we start counting, the i%15 prefixes a # on every 15th line
$0 prints the record (the line) as is
You can type all the text with white spaces skipping the trailing '\' on a single command line.
Or, you can use it as an AWK file,
# File: comment.awk
BEGIN{ i=0; }
$0 ~ {\
if (FNR<31) {print $0} \
else {\
i++; \
if (i%15) {\
print $0
}\
else {\
printf "#%s\n",$0
}\
}\
}
And run it as,
awk -f comment.awk inputfile.txt > outputfile.txt
Hope this will help you to use more AWK.
Python:
f_in = open("file.txt")
f_out = open("file_out.txt","w")
offset = 4 # 0 <= offset < 15 ; first marker after fourth line in this example
for num,line in enumerate(f_in):
if not (num-offset) % 15:
f_out.write("#\n")
f_out.write(line)
Haskell:
offset = 31;
chunk_size = 15;
main = do
{
(h, t) <- fmap (splitAt offset . lines) getContents;
mapM_ putStrLn h;
mapM_ ((putStrLn "#" >>) . mapM_ putStrLn) $
map (take chunk_size) $
takeWhile (not . null) $
iterate (drop chunk_size) t;
}