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
Related
Here is an example given by google of a Named function using recursion
=IF(ISERROR(FIND(" ", str)), str, REVERSE_WORDS(RIGHT(str, LEN(str)-FIND(" ", str)))&" "&LEFT(str, FIND(" ",str)-1))
This function will take "1 2 3 4" and the final output will be "4 3 2 1" but I am trying to understand exactly why this is occurring specifically by taking it step by step and this is what I have so far:
Imaginary Debugging
Step 1
iserror false
Step 2
REVERSE_WORDS( "2 3 4" )
Step 3
iserror false
Step 4
REVERSE_WORDS( "3 4" )
Step 5
iserror false
Step 6
REVERSE_WORDS( "4" )
Step 7?
iserror true so return 4?
Step 8?
???
I don't understand exactly how the final output becomes "4 3 2 1" can someone please write out the remaining steps or correct them for me to visualize since I can't debug/evaluate functions in google sheets. I understand &" "&LEFT(str, FIND(" ",str)-1)) will output 1 then 2 then 3 and then not trigger the forth time because of the iserror but it seems like the output should be "4 1 2 3" or just "4 1" or "4 3".
Recursion is a programming strategy, where a function calls itself. If a function is made to call itself, it can call itself indefinitely. For recursion to return a valid value, the exit strategy should be inside the function itself.
IF(ISERROR(FIND(" ", str)), str, REVERSE_WORDS(RIGHT(str, LEN(str)-FIND(" ", str)))&" "&LEFT(str, FIND(" ",str)-1))
Here, the exit strategy is provided ISERROR. During each recursion, the function checks, if FIND() throws a error, if it throws a error, the function returns the string, else it keeps calling itself. Whenever it calls itself, it leaves a value.
REVERSE_WORDS()&" "&LEFT(str, FIND(" ",str)-1))
Here, it leaves LEFT(str, number of characters) on each call. The number of characters is determined by finding the first space in the string. In the case of
1 2 3 4
Imaginary Debugging
Step 1
iserror false
Return REVERSE_WORDS( "2 3 4" )& " 1"
Step 2
REVERSE_WORDS( "2 3 4" )
iserror false
Return REVERSE_WORDS( "3 4" )& " 2"
Step 3
REVERSE_WORDS( "3 4")
iserror false
Return REVERSE_WORDS( "4" )& " 3"
Step 4
REVERSE_WORDS( "4" )
iserror true so
Return "4"
Note that the first return is the real return or the return we receive from calling REVERSE_WORDS( "1 2 3 4" ). That return is
REVERSE_WORDS( "2 3 4" )& " 1"
The REVERSE_WORDS( "2 3 4" ) call in that first return returns:
REVERSE_WORDS( "3 4" )& " 2"
Combined, the first return can be written as,
REVERSE_WORDS( "3 4" )& " 2"& " 1"
If we keep substituting(recursing), we get,
"4"&" 3"&" 2"&" 1"
which is
4 3 2 1
Why isn't it 1 2 3 4?
Because of the order of operation. If we change
REVERSE_WORDS()&" "&LEFT()
to
LEFT()&" "&REVERSE_WORDS()
We'll get 1 2 3 4
#1 =IF(ISERROR(FIND(" ", str)), str,
#2 REVERSE_WORDS(RIGHT(str, LEN(str)-FIND(" ", str)))
#3 &" "&
#4 LEFT(str, FIND(" ",str)-1))
#1 If there is no space in the input, return the input.
#4 Extract the first element from the input and place it at the end of the output
#2 Extract the string without the first element from the input and recur
#3 Concat the return value of recursion (#2) and the first element (#4) with a space
1st level:
Step
Result
Input
1 2 3 4
#1
False
#4
1
#2
REVERSE_WORDS("2 3 4")
#3
Return of 2nd level 1
2nd level:
Step
Result
Input
2 3 4
#1
False
#4
2
#2
REVERSE_WORDS("3 4")
#3
Return of 3rd level 2
3rd level:
Step
Result
Input
3 4
#1
False
#4
3
#2
REVERSE_WORDS("4")
#3
Return of 4th level 3
4th level:
Step
Result
Input
4
#1
TRUE
#4
4
#2
#3
4
Finally, the return values are concatted as follows:
Level
Return
4th
4
3rd
4 3
2nd
4 3 2
1st
4 3 2 1
I have a step where I need to check certain message. I used a multi-line parameter:
Then I see welcome message: 'Welcome to our site!
Some more text
Even more text'
Problem is that message should have spaces at the end of first and second lines (IDK why, but it should). And JBehave trims spaces from each line. So test fails.
How can I set it not to trim this parameter?
I've tried writing \n instead of actual line-breaks, but it wasn't replaced with line-breaks
Also tried adding {trim=false} in the beginning of parameter, but it reads it as part of the parameter.
Made some experiments with quotation marks (used ", ', none), it didn't help either...
I have tested that and it seems that JBehave actually truncates spaces at the end of the test:
When some step with multitline parameter:first line has 10 spaces at the end
Second line has 6 spaces at the end
Third line has no spaces at the end, but fourth line has 8 spaces
Fifth line has 3 spaces, and Sixth line has only 7 spaces
#When("some step with multitline parameter:$lines")
public void stepWithMultilneString(String s) {
String lines [] = s.split("\\r?\\n");
for(int i = 0; i < lines.length; i++) {
System.out.format("Line %d is: >>%s<<\n", i+1, lines[i]);
}
}
Line 1 is: >>first line has 10 spaces at the end <<
Line 2 is: >>Second line has 6 spaces at the end <<
Line 3 is: >>Third line has no spaces at the end, but fourth line has 8 spaces<<
Line 4 is: >> <<
Line 5 is: >>Fifth line has 3 spaces, and Sixth line has only 7 spaces<<
When some step with multitline parameter:first line has 10 spaces at the end
Second line has 6 spaces at the end
Third line has no spaces at the end, but fourth line has 8 spaces
Fifth line has 3 spaces, and Sixth line has only 7 spaces
I suggest a bypass - a step with delimiters ! at the beginning and end of the text:
When step with multitline parameter surrounded by !:!first line has 10 spaces at the end
Second line has 6 spaces at the end
Third line has no spaces at the end, but fourth line has 8 spaces
Fifth line has 3 spaces, and Sixth line has only 7 spaces
!
#When("step with multitline parameter surrounded by !:$string")
public void stepWithMultilneStringVersion2(String s) {
if( s.startsWith("!")) {
s = s.substring(1);
}
if( s.endsWith("!")) {
s = s.substring(0, s.length()-1);
}
String lines [] = s.split("\\r?\\n");
for(int i = 0; i < lines.length; i++) {
System.out.format("Line %d is: >>%s<<\n", i+1, lines[i]);
}
}
Line 1 is: >>first line has 10 spaces at the end <<
Line 2 is: >>Second line has 6 spaces at the end <<
Line 3 is: >>Third line has no spaces at the end, but fourth line has 8 spaces<<
Line 4 is: >> <<
Line 5 is: >>Fifth line has 3 spaces, and Sixth line has only 7 spaces <<
Line 6 is: >> <<
When step with multitline parameter surrounded by !:!first line has 10 spaces at the end
Second line has 6 spaces at the end
Third line has no spaces at the end, but fourth line has 8 spaces
Fifth line has 3 spaces, and Sixth line has only 7 spaces
!
I have a file text "a.txt" :
1 2 3
4 5 6
7 8 9
Now i want store it in array 2d :
array ={ {1,2,3}{4,5,6}{7,8,9} }
I have try to :
array ={}
file = io.open("a.txt","r")
io.input(file)
i=0
for line in io.lines() do
array[i]=line
i=i+1
end
But it doesn't success.
Does anyone suggest me a way to do it?
You have some errors in your code. You first open the file a.txt and then set it for standard input. You don't need the open(). But i recommend to open the file and operate on it, using the lines() iterator on the file:
array = {}
file = io.open("a.txt","r")
i = 0
for line in file:lines() do
array[i]=line
i=i+1
end
Furthermore, with your method, you don't get the array you wished for ({ {1, 2, 3}, {4, 5, 6}, {7, 8, 9} }) but instead an array containing strings as elements:
{ "1 2 3", "4 5 6", "7 8 9" }.
To get the latter, you have to parse the string you have read. An easy way to do this is to use string.match with captures:
array ={}
file = io.open("a.txt","r")
for line in file:lines() do
-- extract exactly three integers:
local t = { string.match(line, "(%d+) (%d+) (%d+)")) }
table.insert(array, t) -- append row
end
See https://www.lua.org/manual/5.3/manual.html#pdf-string.match. For a arbitrary number of integers (or other numbers) on every line, you can use a loop together with string.gmatch():
array ={}
file = io.open("a.txt","r")
for line in file:lines() do
local t = {}
for num in string.gmatch(line, "(%d+)") do
table.insert(t, num)
end
table.insert(array, t)
end
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"
}
I've found this similar two questions to the one I'm about to ask:
Split array up into n-groups of m size?
and
Need to split arrays to sub arrays of specified size in Ruby
This splits array into three arrays with each array having three elements :
a.each_slice(3) do |x,y,z|
p [x,y,z]
end
So if I do this (my array size is 1000) :
a.each_slice(200) do |a,b,c,d,e|
p "#{a} #{b} #{c} #{d} #{e}"
end
This should split my array into 5 arrays each having 200 members? But it doesn't?
What I actually need to do is to put 200 random elements into 5 arrays, am I on the right track here, how can I do this?
Enumerable#each_slice
If you provide a single argument to the block of each_slice then it will fill that argument with an array of values less than or equal to the given argument. On the last iteration if there are less than n values left then the array size will be whatever is left.
If you provide multiple arguments to the block of each_slice then it will fill those values with the values from the source array. If the slice size is greater than the number of arguments given then some values will be ignored. If it is less than the number of arguments than the excess arguments will be nil.
a = (1..9).to_a
a.each_slice(3) {|b| puts b.inspect }
[1,2,3]
[4,5,6]
[7,8,9]
a.each_slice(4) {|b| puts b.inspect }
[1,2,3,4]
[5,6,7,8]
[9]
a.each_slice(3) {|b,c,d| puts (b + c + d)}
6 # 1 + 2 + 3
15 # 4 + 5 + 6
24 # 7 + 8 + 9
a.each_slice(3) {|b,c| puts (b + c)}
3 # 1 + 2, skips 3
9 # 4 + 5, skips 6
15 # 7 + 8, skips 9
a.each_slice(2) {|b,c| puts c.inspect}
2
4
6
8
nil
a.each_slice(3) {|b,c,d,e| puts e.inspect}
nil
nil
nil
irb(main):001:0> a= (1..10).to_a
=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
irb(main):002:0> a.sample(3)
=> [5, 10, 1]
irb(main):003:0> (1..3).map{ a.sample(3) }
=> [[6, 2, 5], [8, 7, 3], [4, 5, 7]]
irb(main):004:0>
Actually you will return a string with the five elements inserted in it.
You can try something:
a1 = [], a2 = [], a3 = [], a4 = [], a5 = []
a.each_slice(5) do |a,b,c,d,e|
a1 << a
a2 << b
a3 << c
a4 << d
a5 << e
end
You will end up with five arrays containing 200 elements each.
I used the simplest possible syntax to make it clear, you can
make it much more condensed.
If you want to assign that result to 5 different arrays, you could use the splat operator,like this:
a,b,c,d,e = *(1..1000).each_slice(200).to_a