Loop through a group of indexes in groovy until value is found - loops

I have a web service response that provides me a block of data (in a long string), which I split into separate elements using the hard return as the separator. This gives me several sentences or elements (indexes I think), and each one has several data values within each element. For example:
//Gets data from web service response<br>
Def longstring =
"0 * 549 F7 G8 H9
1 2247 F6 G4 H10
17JUN DFWPHX F7
M7 B2 Y1"
//Splits the above into separate sentences/elements
longstring.split("\\r?\\n")
String[] Element=longstring.split("\\r?\\n")
//Print out of elements<br>
Log.info Element[1] = "0 * 549 F7 G8 H9"
Log.info Element[2] = "1 2247 F6 G4 H10"
Log.info Element [3] = "17JUN DFWPHX F7"
Log.info Element[4]= " M7 B2 Y1"
I have written a block of groovy code, which when provided the element ID, the code will try and drill down to get only a certain value within that element. For example, If Element[1], starts with "0" then do "x" thing, else do "y" thing. I need to be able to loop through all the elements (or indexes) with this same code until I come away with the information I need, then exit the iteration/loop once that data has been found.
I am not a groovy expert. I've seen the google results for maps, loops, and different operators. None of them make sense with my scenario. The text in each element is not a list. Mapping and looping seem to require a different set up than what I have. If you can help me solve this, please explain the code in simple terms if possible. Thanks in advance for your time and expertise.

It's a bit hard to understand your need here, but I will give it a try.
Assuming you want some piece of code to be executed based on the pattern of a line. I have an example here for you that tries do achieve this:
//Here I define 2 action closures - what I want to happen
def whenZero = { line ->
println "The line '$line' starts with a zero"
}
def whenOne = {line ->
println "The line '$line' starts with a one"
}
//Then I declare patterns and map them to each of the actions
Map methodMap = ['0.*':whenZero, '1.*':whenOne]
//This method will do the matching of the pattern and call any action
def executeBasedOnKey(Map map, String line){
map.each{ key, method ->
if (line.matches(key)) method(line)
}
}
//Your input
def longstring ="""0 * 549 F7 G8 H9
1 2247 F6 G4 H10
17JUN DFWPHX F7
M7 B2 Y1"""
//This line calls the evaluation for each of the lines
longstring.split("\\r?\\n").each{line->
executeBasedOnKey(methodMap, line)
}

This is the solution that worked for me. I labeled it based upon how I was told it was designed
//String that needs to be split
def longString ="""0 * 549 F7 G8 H9
1 2247 F6 G4 H10
17JUN DFWPHX F7
M7 B2 Y1"""
//Splits the entire string response above into substrings based upon hard returns ("S" becomes the new chopped up strings)
longString.split("\\r?\\n")
String[] S=longString.split("\\r?\\n")
//Creates the variable foundData for the loop to use below
String foundData;
//Creates "subS" variable for all the elements seen in the array "S" from above
for(String subS: S)
{
//Creates a matcher pattern to look in each subelement (subS) where it looks for a regex pattern.
//Description of the regex used: /\d\s+(\d+).*/ = one digit followed by one or more spaces, followed by another one or more digits
//Note that the regex above includes: (\d+). This creates a "group" within the pattern, which is referred to below in the DataMatcher
def DataMatcher = (subS =~ /\d\s+(\d+).*/);
//If the subelement (subS) matches the above pattern, it goes into the below block of code
if (DataMatcher.matches())
{ //Sets the variable foundData (see above) to value of the DataMatcher and only grabs the data needed
//Note that the flightMatcher has two sections [0] and [1]. These represent the following:
//[0] = The entire string should be looked at
//[1] = Only group 1 in that string should be retrieved *See group created (in comments) in the regex portion above
foundData = DataMatcher[0][1];
//This breaks the loop once the Data needed has been matched
break;
}
}
//Displays the foundData needed
log.info foundData

Related

Replacing hard-coded contiguous cells with a loop

This task concerns Google Sheets and a Google Apps Scripts I wrote.
There is a task: we have a table which consists of 1 colomn and 3 rows. Each row (which is a cell also) contains a record of the following type "4d 1a 3c 5e 2b", where each letter can be subsituted by a word. In each row (cell) expressions may or may not repeat the "4d 1a 3c 5e 2b" expression, the distribution of numbers is random.
I need to do the following thing - divide each cell with "4d 1a 3c 5e 2b" type expression into 5 separate cells, sort them in ascending order.
On the one hand, I solved this problem. Firstly I created a variable and assigned the expression from the cell as a value to it. Then I created an array by means of .split(" ") method and sorted the items of the array by .sort() method. As a result I managed to set the values, which were items of sorted array, for a few cells.
Here is the code:
function mySort() {
var dt = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("myPage").getRange("F3").getValue();
var arr = dt.split(" ");
a = arr.sort();
var first = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("myPage").getRange("H3").setValue(arr[0]);
var second = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("myPage").getRange("I3").setValue(arr[1]);
var third =SpreadsheetApp.getActiveSpreadsheet().getSheetByName("myPage").getRange("J3").setValue(arr[2]);
var ddt = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("myPage").getRange("F4").getValue();
var arr2 = ddt.split(" ");
aa = arr2.sort();
var first2 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("myPage").getRange("H4").setValue(arr2[0]);
var second2 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("myPage").getRange("I4").setValue(arr2[1]);
var third2 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("myPage").getRange("J4").setValue(arr2[2]);
var dddt = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("myPage").getRange("F5").getValue();
var arr3 = dddt.split(" ");
aa = arr3.sort();
var first3 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("myPage").getRange("H5").setValue(arr3[0]);
var second3 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("myPage").getRange("I5").setValue(arr3[1]);
var third3 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("myPage").getRange("J5").setValue(arr3[2]);
}
As you can see, everything works: when I push the button with mySort() function assigned I get an appropriate result. However, I would like do more. It would be great if I could select as many rows as I want, then push the button and see how the loop goes through all the rows, splits them, sorts them, and assigns the elements of each sorted array to the cells next to the initial cell. To make it more clear, the final result must look something like this:
"4d 1a 3c 5e 2b" /// "1a" "2b" "3c" "4d" "5e"
"1g 5i 2g 4f 3h" /// "1g" "2g" "3h" "4f" "5i"
"5n 3m 1l 4k 2o" /// "1l" "2o" "3m" "4k" "5n"
So, how can I use loop in Google Sheets which will do such thing without typing in which exactly cell I want to see the items of the sorted array?
I think this will do it for you.
function yourSort(){
var ss=SpreadsheetApp.getActive();
var sh=ss.getSheetByName('myPage');
var rg=sh.getDataRange();
var vA=rg.getValues();
for(var i=2;i<vA.values();i++){
var A=String(vA[i][5]).split(" ").sort();
vA[i][7]=A[0];
vA[i][8]=A[1];
vA[i][9]=A[2];
}
rg.setValues(vA);
}
As long as you have headers for every column and some data on every row then I think getDataRange() will work for you.

Ruby partner pairing program not working?

I am new to ruby and have this program that takes in a number of names and sorting them into pairs of two, and throwing the odd person in a random group. Sometimes it works perfect, sometimes it throws the extra person into an array of their own, and im not sure why. I know there is a cleaner way to do this but Im just trying to understand how the code works. For example it should return "Apple" "Banana" "Orange" as ["Banana", "Orange", "Apple"] and will most of the time, but sometimes it give me ["Banana","Orange",] ["Apple"] Any advice?
def randomArray
classNames = []
puts "Please enter a list of names to sort"
while true
input = gets.chomp
break if input.empty?
classNames << input
end
classRandom = classNames.shuffle
splitNames = classRandom.each_slice(2).to_a
arrayPos = 0
splitNames.length.times do
if splitNames[arrayPos].length == 2
arrayPos+=1
else splitNames[arrayPos].length == 1
splitNames.sample << splitNames[arrayPos].pop
arrayPos+=1
end
end
x = 0
splitNames.length.times do
break if splitNames[x].empty?
puts "Group number #{x+1} is #{splitNames[x]}"
x+=1
end
end
randomArray
Your problem is this: splitNames.sample << splitNames[arrayPos].pop
sample can return any element of the array, including the element that has the odd person you're trying to assign! So if it samples that person, it removes them from their group of 1 and then adds them right back in.
To fix it, take advantage of the fact that either all groups will be pairs, or the last group will have a single person. Don't iterate over the array, just check splitNames[-1]. If they are alone, add them to splitNames[0...-1].sample.

Searching an Array of Cells in Excel

I am trying to search an array of cells in excel to find if it contains a word to then further evaluate.
so for example; I have named the array (A1:A5) as 'cList'.
A1 = apple
A2 = pear
A3 = orange
A4 = banana
A5 = cherry
I want to
=SEARCH("pear",cList)
but i keep getting FALSE - which is not true because it is contained in A2.
My thought here is that Search cannot be used on an array, because if I instead used
=SEARCH("pear",A2)
I will get my desired TRUE.
So is there another way to test an array if it contains and answer?
SEARCH only searches a single cell. The easiest way to find if a range contains a word is just to use COUNTIF
=COUNTIF($A$1:$A$5,"pear")
This tells you how many matches there are, or to get it as a TRUE/FALSE value
=COUNTIF($A$1:$A$5,"pear")>0
You can also use wildcards, so this would find things like "pearmain" and "prickly pear"
=COUNTIF($A$1:$A$5,"*pear*")>0
Sounds like a for loop would work fine...
for(int i=1; i<6; i++){
String cell = "A" + i;
if(SEARCH("pear",cell)
//do things...
}
EDIT: Rereading your question, you'd want to adapt this to loop over your array...

AS3 newbie "match 3" issue - matching types

I'm trying to make a "match 3" game. Instead of just having one type of each jewel that matches, I want to have 2 different types of each jewel that will then match. I've set up my movieclip with 12 frames, comprised of 6 pairs of different jewels, and randomizing which frame will play. I'm using Gary Rosenzweig's code (Actionscript Game Programming University) as a base.
I have 6 different arrays to hold the matching combinations (eg, m1 = [1,2], m2 = [3,4] ... m6 = [11,12]). I've set up my match conditions like this:
Standard match where frame numbers match directly:
if (mc1.currentFrame == mc2.currentFrame) {
match.push(mc2);
Match where frame numbers are different, but they're part of the same pair and should match:
} else if (mc1.currentFrame in m1 && mc2.currentFrame in m1) {
match.push(mc2);
The problem is that I'm not getting any matches from the 2nd condition. I've set traces up for each condition that show the two frame numbers being compared, but pairs that should be matching aren't.
Help!!!! As a complete AS3 newbie, I've tried to figure this out every which way I can, but no luck so far. Any assistance would be greatly appreciated.
Uh, I've never used "in", so there might be some weirdness with that.
Instead of
} else if (mc1.currentFrame in m1 && mc2.currentFrame in m1) {
You might try
} else if (m1.indexOf(mc1.currentFrame)>-1 && m1.indexOf(mc2.currentFrame)>-1) {
Oh, you are also checking mc2 current frame against m1 and not m2. Did you want to do that?

find and delete lines in file python 3

I use python 3
Okay, I got a file that lock like this:
id:1
1
34
22
52
id:2
1
23
22
31
id:3
2
12
3
31
id:4
1
21
22
11
how can I find and delete only this part of the file?
id:2
1
23
22
31
I have been trying a lot to do this but can't get it to work.
Is the id used for the decision to delete the sequence, or is the list of values used for the decision?
You can build a dictionary where the id number is the key (converted to int because of the later sorting) and the following lines are converted to the list of strings that is the value for the key. Then you can delete the item with the key 2, and traverse the items sorted by the key, and output the new id:key plus the formated list of the strings.
Or you can build the list of lists where the order is protected. If the sequence of the id's is to be protected (i.e. not renumbered), you can also remember the id:n in the inner list.
This can be done for a reasonably sized file. If the file is huge, you should copy the source to the destination and skip the unwanted sequence on the fly. The last case can be fairly easy also for the small file.
[added after the clarification]
I recommend to learn the following approach that is usefull in many such cases. It uses so called finite automaton that implements actions bound to transitions from one state to another (see Mealy machine).
The text line is the input element here. The nodes that represent the context status are numbered here. (My experience is that it is not worth to give them names -- keep them just stupid numbers.) Here only two states are used and the status could easily be replaced by a boolean variable. However, if the case becomes more complicated, it leads to introduction of another boolean variable, and the code becomes more error prone.
The code may look very complicated at first, but it is fairly easy to understand when you know that you can think about each if status == number separately. This is the mentioned context that captured the previous processing. Do not try to optimize, let the code that way. It can actually be human-decoded later, and you can draw the picture similar to the Mealy machine example. If you do, then it is much more understandable.
The wanted functionality is a bit generalized -- a set of ignored sections can be passed as the first argument:
import re
def filterSections(del_set, fname_in, fname_out):
'''Filtering out the del_set sections from fname_in. Result in fname_out.'''
# The regular expression was chosen for detecting and parsing the id-line.
# It can be done differently, but I consider it just fine and efficient.
rex_id = re.compile(r'^id:(\d+)\s*$')
# Let's open the input and output file. The files will be closed
# automatically.
with open(fname_in) as fin, open(fname_out, 'w') as fout:
status = 1 # initial status -- expecting the id line
for line in fin:
m = rex_id.match(line) # get the match object if it is the id-line
if status == 1: # skipping the non-id lines
if m: # you can also write "if m is not None:"
num_id = int(m.group(1)) # get the numeric value of the id
if num_id in del_set: # if this id should be deleted
status = 1 # or pass (to stay in this status)
else:
fout.write(line) # copy this id-line
status = 2 # to copy the following non-id lines
#else ignore this line (no code needed to ignore it :)
elif status == 2: # copy the non-id lines
if m: # the id-line found
num_id = int(m.group(1)) # get the numeric value of the id
if num_id in del_set: # if this id should be deleted
status = 1 # or pass (to stay in this status)
else:
fout.write(line) # copy this id-line
status = 2 # to copy the following non-id lines
else:
fout.write(line) # copy this non-id line
if __name__ == '__main__':
filterSections( {1, 3}, 'data.txt', 'output.txt')
# or you can write the older set([1, 3]) for the first argument.
Here the output id-lines where given the original number. If you want to renumber the sections, it can be done via a simple modification. Try the code and ask for details.
Beware, the finite automata have limited power. They cannot be used for the usual programming languages as they are not able to capture nested paired structures (like parenteses).
P.S. The 7000 lines is actually a tiny file from a computer perspective ;)
Read each line into an array of strings. The index number is the line number - 1. Check if the line equals "id:2" before you read the line. If yes, then stop reading the line until the line equals "id:3". After reading the line, clear the file and write the array back to the file until the end of the array. This may not be the most efficient way but should work.
if there isn't any values in between that would interfere this would work....
import fileinput
...
def deleteIdGroup( number ):
deleted = False
for line in fileinput.input( "testid.txt", inplace = 1 ):
line = line.strip( '\n' )
if line.count( "id:" + number ): # > 0
deleted = True;
elif line.count( "id:" ): # > 0
deleted = False;
if not deleted:
print( line )
EDIT:
sorry this deletes id:2 and id:20 ... yuo could modify it so that the first if checks - line == "id:" + number

Resources