Using Groovy, I wish to grab two parts of a tab-separated line. Take the example line:
one fish two fish red fish blue fish ----(each character tab /t separated)
Suppose I want to print one and then I want to print red fish blue
How can I do this?
Alternatively, suppose I want to print one and then a count of the number of characters (words) following red? Or between two and blue?
A previous question yielded this response for printing everything following a certain part of the line:
c = ~/.*red(.*)/
m = line =~ c
if (m) {
println m[0][1]
}
to yield fish blue fish but I'm not comptetent enough with regex's to modify this appropriately. I've tried a few iterations, inserting /t in there and modifying my capturing expression but I've not figured it out. This is three or four questions in one, any help is appreciated. Thanks!!
def a = [:].withDefault{[]}
def b = [:].withDefault{[]}
def c = 0
def d = 0
def e = 0
def f = 0
seuss = "one\tfish\ttwo\tfish\tred\tfish\tblue\tfish"
a = seuss.split (/\t/)
for (i =0; i<a.size(); i++) {
if (d != 0) {
c = c + 1
}
if ( a[i] == "red") {
d = i
}
}
println a[4] + '\t' + c
for (i =0; i<a.size(); i++) {
if ( a[i] == "blue") {
e = 0
}
if (e != 0) {
f = f + 1
}
if ( a[i] == "two") {
e = i
}
}
println a[0] + '\t' + f
Related
I was looking at some code which came with the following short-hand statement
score = ((initialPlayer == player) ? CAPTURE_SCORE : -CAPTURE_SCORE) + recursive_solver(lastMap, initialPlayer, findOpponent(player), 1 + rounds);
I think that I understand the first portion of the code,
if(initialPlayer == player){
score = CAPTURE_SCORE;
}
else
score = -CAPTURE_SCORE;
but im confused to how the +recursive_solver function is added to this, any help would be greatly appreciated :)
As stated above I tried to write out the statement in a longer from thats easier for me to read. My best guess is that the recursive solver function is then added to the score of the if-else statement?
if(initialPlayer == player)
score = CAPTURE_SCORE + recursive_solver(lastMap, initialPlayer, findOpponent(player), 1 + rounds);
else
score = -CAPTURE_SCORE + recursive_solver(lastMap, initialPlayer, findOpponent(player), 1 + rounds);
Explanation:
A = (C ? B : D) + E;
If C is true: A = (B) + E;
If C is false: A = (D) + E;
In sum
if (C)
A = B + E;
else // if (!C)
A = D + E;
score = ((initialPlayer == player) ? CAPTURE_SCORE : -CAPTURE_SCORE) + recursive_solver(lastMap, initialPlayer, findOpponent(player), 1 + rounds);
Equals to
if(initialPlayer == player) {
score = CAPTURE_SCORE;
} else {
score = -CAPTURE_SCORE;
}
score += recursive_solver(lastMap, initialPlayer, findOpponent(player), 1 + rounds);
So I am trying to split characters a certain way.
If I provide this string:
text (text (adsf (asdfasdfjkl) asdfjlkasdjf) stuff) (morestuff stuff)
I want it to split it into:
['text', '(text (adsf (asdfasdfjkl) asdfjlkasdjf) stuff)', '(morestuff stuff)']
Code I had:
def pair_char(left, right, start, text, exclusive=False, verbose=False):
package = []
for e, c in enumerate(text):
left_c = right_c = 0
if text[e] == left:
left_c += 1
marker = start = e
while text[marker+1] != right or left_c > right_c:
marker += 1
if verbose:
print left_c, right_c, text[marker], left, right, text[marker]==left, text[marker]==right
if marker+1 >= len(text):
break
if text[marker] == left_c:
print "left_c"
left_c += 1
if text[marker] == right_c:
print "right_c"
right_c += 1
end = marker
if exclusive:
package.append(text[start+1:end])
else:
package.append(text[start:end+1])
e = end
package = "".join(package)
return package
Any suggestions?
So, basically, in Excel, I have 4 columns of data (all with strings) that I want to process, and want to have the results in another column, like this (nevermind the square brackets, they just represent cells):
Line Column1 Column2 Column3 Column4 Result
1: [a] [b] [k] [YES] [NO]
2: [a] [c] [l] [YES] [NO]
3: [b] [e] [] [YES] [NO]
4: [c] [e] [f] [NO] [NO]
5: [d] [h] [b] [NO] [NO]
6: [d] [] [w] [NO] [NO]
7: [e] [] [] [YES] [NO]
8: [j] [m] [] [YES] [YES]
9: [j] [] [] [YES] [YES]
10: [] [] [] [YES] [YES]
The process that I want the data to go through is this:
Assume that CheckingLine is the Line for which I currently want to calculate the value of Result, and that CurrentLine is any Line (except CheckingLine) that I am using to calculate the value of Result, at a given moment.
If Column4[CheckingLine] is "NO", Result is "NO" (simple enough, no help needed);
Example: CheckingLine = 1 -> Column4[1] = "NO" -> Result = "NO";
Else, I want to make sure that all Lines that share a common value with CheckingLine (in any Column between 1 and 3), also have Column4 as "YES" (Doing that would be simple enough even without VBA - in fact, I started by doing it in plain Excel and realised that it wasn't what I wanted) - if that happens, Result is "YES";
Example: CheckingLine = 8 -> Only shared value is "j" -> CurrentLine = 9 -> Column4[9] = "YES" -> Result = "YES";
Here's the tricky part: If one of those lines has any value (again, in any Column between 1 and 3) that IS NOT shared with CheckingLine, I want to do the whole process (restart at 1.), but checking the CurrentLine instead.
Example: CheckingLine = 2, "a" is shared with Line 1, c is shared with Line 4 -> CurrentLine = 1 -> Column4[1] = "YES", but "b" and "k" are not shared with CheckingLine -> CheckingLine' = 1 -> "b" is shared with Line 5 -> Column4[5] = "NO" -> Result = "NO";
I have written the corresponding C++ code (which works) (and it could have been in any other language, C++ was just the one I was using at the moment) (and the code HAS NOT been optimized in any way, because it's purpose was to be AS CLEAR about its functionality AS POSSIBLE) (the table above is the actual result of running it):
#include <iostream>
#include <string>
#include <vector>
std::vector<std::string> column1, column2, column3, column4, contentVector;
unsigned int location, columnsSize;
void InsertInVector(std::string Content)
{
if(Content == "")
{
return;
}
for(unsigned int i = 0; i < contentVector.size(); i++)
{
if(contentVector[i] == Content)
{
return;
}
}
contentVector.push_back(Content);
}
std::string VerifyCurrentVector(unsigned int Start)
{
std::string result = "";
if(contentVector.size() == 0)
{
result = "YES";
}
else
{
unsigned int nextStart = contentVector.size();
for(unsigned int i = 0; i < columnsSize; i++)
{
if(i != location)
{
for(unsigned int j = Start; j < nextStart; j++)
{
if(column1[i] == contentVector[j])
{
InsertInVector(column2[i]);
InsertInVector(column3[i]);
}
else if(column2[i] == contentVector[j])
{
InsertInVector(column1[i]);
InsertInVector(column3[i]);
}
else if(column3[i] == contentVector[j])
{
InsertInVector(column1[i]);
InsertInVector(column2[i]);
}
}
}
}
if(nextStart == contentVector.size())
{
for(unsigned int i = 0; i < columnsSize; i++)
{
if(i != location)
{
for(unsigned int j = 0; j < nextStart; j++)
{
if(column1[i] == contentVector[j] || column2[i] ==
contentVector[j] || column3[i] == contentVector[j])
{
if(column4[i] == "NO")
{
result = "NO";
return result;
}
}
}
}
}
result = "YES";
}
else
{
result = VerifyCurrentVector(nextStart);
}
}
return result;
}
std::string VerifyCell(unsigned int Location)
{
std::string result = "";
location = Location - 1;
if(column4.size() < Location)
{
result = "Error";
}
else if(column4[location] == "NO")
{
result = "NO";
}
else
{
contentVector.clear();
InsertInVector(column1[location]);
InsertInVector(column2[location]);
InsertInVector(column3[location]);
result = VerifyCurrentVector(0);
}
return result;
}
void SetUpColumns(std::vector<std::string> &Column1, std::vector<std::string> &Column2,
std::vector<std::string> &Column3, std::vector<std::string> &Column4)
{
if(Column4.size() > Column1.size())
{
for(unsigned int i = Column1.size(); i < Column4.size(); i++)
{
Column1.push_back("");
}
}
if(Column4.size() > Column2.size())
{
for(unsigned int i = Column2.size(); i < Column4.size(); i++)
{
Column2.push_back("");
}
}
if(Column4.size() > Column3.size())
{
for(unsigned int i = Column3.size(); i < Column4.size(); i++)
{
Column3.push_back("");
}
}
column1 = Column1;
column2 = Column2;
column3 = Column3;
column4 = Column4;
columnsSize = Column4.size();
}
int main()
{
std::vector<std::string> Column1, Column2, Column3, Column4;
Column1.push_back("a");
Column1.push_back("a");
Column1.push_back("b");
Column1.push_back("c");
Column1.push_back("d");
Column1.push_back("d");
Column1.push_back("e");
Column1.push_back("j");
Column1.push_back("j");
Column2.push_back("b");
Column2.push_back("c");
Column2.push_back("e");
Column2.push_back("e");
Column2.push_back("h");
Column2.push_back("");
Column2.push_back("");
Column2.push_back("m");
Column3.push_back("k");
Column3.push_back("l");
Column3.push_back("");
Column3.push_back("f");
Column3.push_back("b");
Column3.push_back("w");
Column4.push_back("YES");
Column4.push_back("YES");
Column4.push_back("YES");
Column4.push_back("NO");
Column4.push_back("NO");
Column4.push_back("NO");
Column4.push_back("YES");
Column4.push_back("YES");
Column4.push_back("YES");
Column4.push_back("YES");
SetUpColumns(Column1, Column2, Column3, Column4);
std::cout << "Line\t" << "Column1\t" << "Column2\t" << "Column3\t" << "Column4\t" <<
std::endl;
for(unsigned int i = 0; i < Column4.size(); i++)
{
std::cout << i + 1 << ":\t" << "[" << column1[i] << "]\t[" << column2[i] <<
"]\t[" << column3[i] << "]\t[" << column4[i] << "]\t[" << VerifyCell(i + 1)
<< "]" << std::endl;
}
return 0;
}
So, after this lengthy explanation, what I want to know is this:
Is there any way to do this in Excel's VBA (or even better, in plain Excel without VBA)?
If not, how can I have my code (which I can easily translate to another C-like language and/or optimise) get the data from, and deliver the results to, Excel?
Is there any way to do this in Excel's VBA?
Yes, you can surely do this with VBA, it is a complete and powerful programming language
(or even better, in plain Excel without VBA)?
Nope. The calculation seems too complicated to fit with Excel formulae without any VBA code.
If not, how can I have my code (which I can easily translate to another C-like language and/or optimise) get the data from, and deliver the results to, Excel?
You can access Excel from C++ in many ways. Using ATL is one of them. another, easier way would be to import/export your Excel file in CSV format, which is easy to parse and write from C++.
Also consider C#, it has complete COM inter-operability to access office components.
Ok, if you like to "whipped the code in a rush" then you'll love VBA, next time please try to ask a more specific question. Based on code and comments #MikeAscended you're a relatively good programmer, with a grasp of functions/recursion, variable/parameters, conditions, loops, data structures, etc. Re: " I have only touched VBA once in my life and ran away from it" My intent is to get you started and give you syntax here not necessarily a working solution. I'm happy to answer any further specific questions you may continue to have.
Strategy-wise,
I recommend plain VBA which is easy to use in Excel. Obviously your problem can be solved in many ways including formulas, however VBA is a powerful tool that any programmer will benefit from using.
Code-wise,
To start access the editor from Excel press [Alt-F11], or from Design Mode insert and double-click an ActiveX button. To run a macro press [Alt-F8], or in VBA click the green play button.
One last note, if you want those line numbers in column 1 in excel then yours will become Column 2-5 or B-F. I'm assuming you'll use the row numbers in excel so that Column 1 is A, but row 1 will still have titles, so you are staring your data on row 2.
sub processResults_Col5()
' Run This Script as Main()
dim rowCount as long, i as long 'rowCount = columnsSize
with sheets(1)
.Range("A1:D1") = Array("a", "b", "k", "YES")
' finish init here
' SetUpColumns not necessary in excel
if .cells(2,1).value <> "" then 'do not use .end(xldown) if data is missing
rowCount = .cells(1,1).end(xldown).row
for i = 1 to rowCount
.cells(i,5) = verifyCell(i + 1, rowCount)
next i
endif 'space will be added :p
end with
end sub
function verifyCell(rowLocation as long, size as long, optional wSh as excel.worksheet) as string
' the rest should be easy for you to figure out based on C-code
with wSh
if wsh is nothing then set wsh = activesheet 'let VBA capitalize stuff so you know you typed it correctly
if size < rowlocation then
verifyCell = "Error" 'the function name is the return value
'msgbox "Error" ' you can uncomment this line to see error
elseif cells(rowLocation, 4).value = "NO" then
cells(rowLocation, 5) = "NO" 'set result
else
call InsertInVector(rowLocation) 'CheckingLine
' edit the current rowLocation with for loops
verifyCell = VerifyCurrentVector(0) 'whatever you're doing here
endif
end with
end function
sub InsertInVector()
end sub
sub VerifyCurrentVector() 'function returns a value
end sub
Some tips:
Generally, Comment Your Code!
Generally, The first word/acronym of Variable and Object names should start in lowercase, then continue in camel-case. This helps distinguish them from library types.
In VBA always put [option explicit] in the beginning of every sheet/module, this requires you to [dim varName as Type] which will help debugging and make your code more explicit so it's easy to understand.
In VBA for numbers use type Long, learn early vs late-binding. If you're instantiating any object that requires a reference/library, always state it explicitly. This includes Excel.Worksheet, Excel.Workbook, etc. (eg. you may want your code in MS Access)
In Office One of the first settings you're going to want to disable is the popup error window, also use debug.print and the immediate box a few times.
Generally, as you know from C++ take your time, try to write correct code on your the first try as this will save you debugging time. Try not to rush and keep coffee & healthy snacks on hand. Good luck and have fun :)
i am having trouble with aligning outcome values.
Alist = ["1,25,999",
"123.4,56.7890,13.571",
"1,23.45,6,7.8"]
c = 0
while c < len(Alist):
r = 0
tokens = Alist[c].split(',')
while r < len(Alist[c].split(',')):
if '.' in tokens[r]:
print "%7.2f" %float(tokens[r]), " ",
else :
print "%3d" %float(tokens[r]), " ",
r += 1
print
c += 1
I want to print such as
1 25 999
123.40 56.79 13.57
1 23.45 6. 7.80
but somehow it is printing
1
25
999
123.40
56.79
13.57
1
23.45
6
7.8
and i cannot figure out what is wrong with my coding.
after the r+1, you have a lone print statement. it is at the wrong indention level - move it to the left by 4 spaces (or one tab) and it should work fine.
The print statement should'nt in the 2nd while loop. just:
Alist = ["1,25,999",
"123.4,56.7890,13.571",
"1,23.45,6,7.8"]
c = 0
while c < len(Alist):
r = 0
tokens = Alist[c].split(',')
while r < len(Alist[c].split(',')):
if '.' in tokens[r]:
print "%7.2f" %float(tokens[r]), " ",
else :
print "%3d" %float(tokens[r]), " ",
r += 1
print
c += 1
In [59]: %paste
myList = ["1,25,999",
"123.4,56.7890,13.571",
"1,23.45,6,7.8"]
rows = [r.split(',') for r in myList]
widths = {i:max(len(c) for c in col) for i,col in enumerate(itertools.izip_longest(*rows, fillvalue=""))}
for row in rows:
for i,val in enumerate(row):
print " "*((widths[i] - len(val))/2), val, " "*((widths[i] - len(val))/2) if not (widths[i]-len(val))%2 else " "*((widths[i] - len(val)+1)/2),
print
## -- End pasted text --
1 25 999
123.4 56.7890 13.571
1 23.45 6 7.8
I solved my problem in an imperative style, but it looks very ugly. How can I make it better (more elegant, more concise, more functional - finally its Scala). Rows with the same values as the previous row, but with a different letter should be skipped, all other values of the rows should be added.
val row1 = new Row(20, "A", true) // add value
val row2 = new Row(30, "A", true) // add value
val row3 = new Row(40, "A", true) // add value
val row4 = new Row(40, "B", true) // same value as the previous element & different letter -> skip row
val row5 = new Row(60, "B", true) // add value
val row6 = new Row(70, "B", true) // add value
val row7 = new Row(70, "B", true) // same value as the previous element, but the same letter -> add value
val rows = List(row1, row2, row3, row4, row5, row6, row7)
var previousLetter = " "
var previousValue = 0.00
var countSkip = 0
for (row <- rows) {
if (row.value == previousValue && row.letter != previousLetter) {
row.relevant = false
countSkip += 1
}
previousLetter = row.letter
previousValue = row.value
}
// get sum
val sumValue = rows.filter(_.relevant == true).map(_.value) reduceLeftOption(_ + _)
val sum = sumValue match {
case Some(d) => d
case None => 0.00
}
assert(sum == 290)
assert(countSkip == 1)
Thanks in advance
Twistleton
(rows.head :: rows).sliding(2).collect{
case List(Row(v1,c1), Row(v2,c2)) if ! (v1 == v2 && c1 != c2) => v2 }.sum
I think the shortest (bulletproof) solution when Row is a case class (dropping the boolean) is
(for ((Row(v1,c1), Row(v2,c2)) <- (rows zip rows.take(1) ::: rows) if (v1 != v2 || c1 == c2)) yield v1).sum
Some of the other solutions don't handle the list-is-empty case, but this is largely because sliding has a bug where it will return a partial list if the list is too short. Clearer to me (and also bulletproof) is:
(rows zip rows.take(1) ::: rows).collect{
case (Row(v1,c1), Row(v2,c2)) if (v1 != v2 || c1 == c2) => v1
}.sum
(which is only two characters longer if you keep it on one line). If you need the number skipped also,
val indicated = (rows zip rows.take(1) ::: rows).collect {
case (Row(v1,c1), Row(v2,c2)) => (v1, v1 != v2 || c1 == c2)
}
val countSkip = indicated.filterNot(_._2).length
val sum = indicated.filter(_._2).map(_._1).sum
Fold it:
scala> rows.foldLeft((row1, 0))((p:(Row,Int), r:Row) => (r, p._2 + (if (p._1.value == r.value && p._1.letter != r.letter) 0 else r.value)))._2
res2: Int = 290
(new Row(0, " ", true) +: rows).sliding(2).map { case List(r1, r2) =>
if (r1.value != r2.value || r1.letter == r2.letter) { r2.value }
else { 0 }
}.sum
Of course you can drop the boolean member of Row if you do not need it for something else
Reduce it:
rows.reduceLeft { (prev, curr) =>
if (prev.value == curr.value && prev.letter != curr.letter) {
curr.relevant = false
countSkip += 1
}
curr
}