Below code is throwing an IndexOutOfBoundsException at line Field f = getField(counter);
Why is it being thrown ? Surely the field exists because I am looping based on fieldcount. Or is the list fields in the manager not gauranteed to be sequential? If this is the case how should I delete fields from a screen that are of type - MyButtonField
Thanks
int fieldCount = getFieldCount() - 1;
if(fieldCount > 1){
for(int counter = 0; counter <= fieldCount ; ++counter){
Field f = getField(counter);
if(f instanceof MyButtonField){
delete(f);
}
}
}
You haven't specified what delete(f) does, but if it removes it from the list of fields, then your "valid count" will effectively decrease.
To rewrite this somewhat and fix the problem:
for (int index = getFieldCount() - 1; index >= 0; index--){
Field f = getField(index);
if (f instanceof MyButtonField) {
delete(f);
}
}
This will go from the end of the fields instead of the start, so it doesn't matter if you remove an entry and everything shuffles up - the items which shuffle up will be the ones you've already looked at.
The best way is to use Iterator for iteration then call the method remove().
Example:
for(Iterator it = getFields().iterator();it.hasNext()){
Field f = (Field) it.next();
if(f instanceof MyButtonField){
it.remove();
}
}
The method getFields() has to return a collection of Field elements.
Related
I'm currently using this formula to highlight duplicates in my spreadsheet.
=ARRAYFORMULA(COUNTIF(A$2:$A2,$A2)>1)
Quite simple, it allows me to skip the first occurrence and only highlight 2nd, 3rd, ... occurrences.
I would like the formula to go a bit further and highlight near duplicates as well.
Meaning if there is only one character difference between 2 cells, then it should be considered as a duplicate.
For instance: "Marketing", "Marketng", "Marketingg" and "Market ing" would all be considered the same.
I've made a sample sheet in case my requirement is not straightforward to understand.
Thanks in advance.
Answer
Unfortunately, it is not possible to do this only through Formulas. Apps Scripts are need as well. The process for achieving your desired results is described below.
In Google Sheets, go to Extensions > Apps Script, paste the following code1 and save.
function TypoFinder(range, word) { // created by https://stackoverflow.com/users/19361936
if (!Array.isArray(range) || word == "") {
return false;
}
distances = range.map(row => row.map(cell => Levenshtein(cell, word))) // Iterate over range and check Levenshtein distance.
var accumulator = 0;
for (var i = 0; i < distances.length; i++) {
if (distances[i] < 2) {
accumulator++
} // Keep track of how many times there's a Levenshtein distance of 0 or 1.
}
return accumulator > 1;
}
function Levenshtein(a, b) { // created by https://stackoverflow.com/users/4269081
if (a.length == 0) return b.length;
if (b.length == 0) return a.length;
// swap to save some memory O(min(a,b)) instead of O(a)
if (a.length > b.length) {
var tmp = a;
a = b;
b = tmp;
}
var row = [];
// init the row
for (var i = 0; i <= a.length; i++) {
row[i] = i;
}
// fill in the rest
for (var i = 0; i < b.length; i++) {
var prev = i;
for (var j = 0; j < a.length; j++) {
var val;
if (b.charAt(i) == a.charAt(j)) {
val = row[j]; // match
} else {
val = Math.min(row[j] + 1, // substitution
prev + 1, // insertion
row[j + 1] + 1); // deletion
}
row[j] = prev;
prev = val;
}
row[a.length] = prev;
}
return row[a.length];
}
In cell B1, enter =TypoFinder($A$2:$A2,$A2). Autofill that formula down the column by draggin.
Create a conditional formatting rule for column A. Using Format Rules > Custom Formula, enter =B2:B.
At this point, you might wish to hide column B. To do so, right click on the column and press Hide Column.
The above explanation assumes the column you wish to highlight is Column A and the helper column is column B. Adjust appropriately.
Note that I have assumed you do not wish to highlight repeated blank columns as duplicate. If I am incorrect, remove || word == "" from line 2 of the provided snippet.
Explanation
The concept you have described is called Levenshtein Distance, which is a measure of how close together two strings are. There is no built-in way for Google Sheets to process this, so the Levenshtein() portion of the snippet above implements a custom function to do so instead. Then the TypoFinder() function is built on top of it, providing a method for evaluating a range of data against a specified "correct" word (looking for typos anywhere in the range).
Next, a helper column is used because Sheets has difficulties parsing custom formulas as part of a conditional formatting rule. Finally, the rule itself is implemented to check the helper column's determination of whether the row should be highlighted or not. Altogether, this highlights near-duplicate results in a specified column.
1 Adapted from duality's answer to a related question.
I have a List of the type Model. when I loop all its elements and loop the next one except for the last one, then change the last one manually, the one before changes.
here is a little code to reproduce the problem (also you can run it directly in dartpad from here)
void main() {
List<Model> s = [];
for (int i = 0; i < 5; i++) {
s.add(Model(i));
}
for (int i = 0; i < s.length - 1; i++) {
s[i] = s[i + 1];
}
print(s);
s[s.length-1].x = 100;
print(s);
}
class Model {
int x;
Model(this.x);
#override
String toString() => 'x: ' + this.x.toString();
}
notice that this problem does not happen when you comment out the for loop or the manual change, or instead of changing the last one's property, you reassign a new value to it, like s[s.length - 1] = Model(100);. seems like dart for some reason is re-running the loop.
When you run the second for loop, you assign the i + 1th Model to the ith position in the list:
// initialise list
for (int i = 0; i < s.length; i++) {
s[i] = s[i + 1]
}
If you unwrap the loop, it looks roughly like this:
s[0] = s[1];
s[1] = s[2];
s[2] = s[3];
s[3] = s[4];
Notice that this leaves s[4] unchanged, but also assigns it to s[3].
In Dart, variables contain references to objects. This means that when your list runs s[3] = s[4];, both s[3] and s[4] point to the same object.
Now, if you modify s[4] you, are actually modifying the objects that s[4] refers to, which happens to also be the object that s[3] refers to, so they both appear to change in your list.
I'm getting "null Skip parameter was passed into argument position 1" error for lines 50 and 89 where I want to put the target/source module names into a skip list. I know the loop only executes if there is the out/in link (respectively), so how can it have a null parameter? I also check for the module name to be null, but the check does not make the error box pop up. Both loops execute for a certain number of objects and then stop when it gets to a particular point it doesn't like. Any tips would be appreciated.
/*
Counts the number of non-obsolete requirements in a module and generates a count of number of objects with in/out links, organized by module name. Output is to a CSV file.
*/
pragma runLim, 0 //turn off timeout dialog
filtering off
Module m = current
/***********************
populateBuffer
************************/
void populateBuffer(Buffer &b)
{
Object o = null
Link l
LinkRef lr
ModName_ srcMod
ModName_ tarMod
string targetMod
string sourcMod
int count = 0
int outTotal = 0
int inTotal = 0
int i = 0
int n = 0
Skip OinLinks = createString
Skip OoutLinks = createString
Skip MinLinks = createString
Skip MoutLinks = createString
Skip OutOrphans = create //list of object abs nos which do not have any out links
Skip InOrphans = create //list of object abs nos which do not have any in links
string s = ""
for o in m do
{
if ((o."URB Object Type" "" == "Requirement") && (o."TIS Status" "" != "Obsolete")) //always cast an attribute value as a string with empty quotes
{
for l in o->"*" do //for out links
{
tarMod = target(l)
targetMod = name(tarMod) //puts the target module of the current link into a string
if (null targetMod) {errorBox "FAILURE FINDING TARGET MODULE!"; halt}
print targetMod "\n"
put(OoutLinks, targetMod, count + 1) //puts all of the targetMods into the OoutLinks skip list
n++
}
if (n > 0) //check if this object has outlinks
{
for count in OoutLinks do//for each unique outlink target module of the current object
{
if (find(MoutLinks, targetMod, i)) //if there is already a matching entry
{
delete(MoutLinks, targetMod) //remove the entry for that particular module name
put(MoutLinks, targetMod, i+1) //and re-enter it with count+1 in module level skip list
}
else {put(MoutLinks, targetMod, 1)} //if it is a new entry, add it with count 1
}
}
else //if there are no outlinks,
{
int absno = o."Absolute Number"
put(OutOrphans, absno, 1) //This adds the absno of the current object to
//our orphan list
}
n = 0
for lr in o <-"*" do //for in links
{
sourcMod = name(source lr) //puts the source module of the current link into a string
if (null sourcMod) {errorBox "FAILURE FINDING SOURCE MODULE!"; halt}
print sourcMod "\n"
print "Source Modules \n"
put(OinLinks, sourcMod, count + 1) //puts all of the sourcMods into the OinLinks skip list
n++
}
if (n > 0) //check if this object has inlinks
{
for count in OinLinks do//for each unique inlink target module of the current object
{
if (find(MinLinks, sourcMod, i)) //if there is already a matching entry
{
delete(MinLinks, sourcMod) //remove the entry for that particular module name
put(MinLinks, sourcMod, i+1) //and re-enter it with count+1 in module level skip list
}
else {put(MinLinks, sourcMod, 1)} //if it is a new entry, add it with count 1
}
}
else //if there are no inlinks,
{
int absno = o."Absolute Number"
put(InOrphans, absno, 1) //This adds the absno of the current object to
//our orphan list
}
delete(OinLinks) //reset the OinLinks list so we can start fresh for the next object
delete(OoutLinks) //reset the OoutLinks list so we can start fresh for the next object
n = 0
}
else continue
}
}
/************************************
MAIN
*************************************/
string fName = "C:/Temp/LinkedObjectsInventory_Jan8.csv"
Stream outfile = write(fName)
Buffer b = create
populateBuffer(b)
outfile << b
close(outfile)
delete(b)
// notify the user that the script is complete
ack "Inventory Complete."
This is a pretty straightforward issue-
The change I would make- replace this:
delete(OinLinks) //reset the OinLinks list so we can start fresh for the next object
delete(OoutLinks) //reset the OoutLinks list so we can start fresh for the next object
with this:
for count in OinLinks do //reset the OinLinks list so we can start fresh for the next object
{
delete ( OinLinks , ( string key OinLinks ) )
}
for count in OoutLinks do //reset the OoutLinks list so we can start fresh for the next object
{
delete ( OoutLinks , ( string key OoutLinks ) )
}
As part of your for each object loop, you were deleting the entire skip list rather than emptying it. This meant that on a subsequent loop, the program could not find the Skip list and threw an error. It's good to reuse skips rather than re-allocate them each time, but you have to empty the contents rather than call delete on the skip handle.
Good luck, and let me know if you have other issues!
I have 30 columns and 1000 rows, I would like to compare column1 with another column. IF the value dont match then I would like to colour it red. Below is a small dataset in my spreadsheet:
A B C D E F ...
1 name sName email
2
3
.
n
Because I have a large dataset and I want to storing my columns in a array, the first row is heading. This is what I have done, however when testing I get empty result, can someone correct me what I am doing wrong?
var index = [];
var sheet = SpreadsheetApp.getActiveSheet();
function col(){
var data = sheet.getDataRange().getValues();
for (var i = 1; i <= data.length; i++) {
te = index[i] = data[1];
Logger.log(columnIndex[i])
if (data[3] != data[7]){
// column_id.setFontColor('red'); <--- I can set the background like this
}
}
}
From the code you can see I am scanning whole spreadsheet data[1] get the heading and in if loop (data[3] != data[7]) compare two columns. I do have to work on my colour variable but that can be done once I get the data that I need.
Try to check this tutorial if it can help you with your problem. This tutorial use a Google AppsScript to compare the two columns. If differences are found, the script should point these out. If no differences are found at all, the script should put out the text "[id]". Just customize this code for your own function.
Here is the code used to achieve this kind of comparison
function stringComparison(s1, s2) {
// lets test both variables are the same object type if not throw an error
if (Object.prototype.toString.call(s1) !== Object.prototype.toString.call(s2)){
throw("Both values need to be an array of cells or individual cells")
}
// if we are looking at two arrays of cells make sure the sizes match and only one column wide
if( Object.prototype.toString.call(s1) === '[object Array]' ) {
if (s1.length != s2.length || s1[0].length > 1 || s2[0].length > 1){
throw("Arrays of cells need to be same size and 1 column wide");
}
// since we are working with an array intialise the return
var out = [];
for (r in s1){ // loop over the rows and find differences using diff sub function
out.push([diff(s1[r][0], s2[r][0])]);
}
return out; // return response
} else { // we are working with two cells so return diff
return diff(s1, s2)
}
}
function diff (s1, s2){
var out = "[ ";
var notid = false;
// loop to match each character
for (var n = 0; n < s1.length; n++){
if (s1.charAt(n) == s2.charAt(n)){
out += "–";
} else {
out += s2.charAt(n);
notid = true;
}
out += " ";
}
out += " ]"
return (notid) ? out : "[ id. ]"; // if notid(entical) return output or [id.]
}
For more information, just check the tutorial link above and this SO question on how to compare two Spreadsheets.
I have a method that fills up the elements of an int[,]. The elements that need to be filled are stored in a .txt file like this:
1
1
2
2
Meaning that I have to fill up the [1,1] and [2,2] element.
For this I use this but it gives the error above
int x = 0;
int y = 0;
for (int i = 0; i < 2; i++)
{
x = int.Parse(SR.ReadLine());
y = int.Parse(SR.ReadLine());
mezo.mezo[x, y] = 1;
}
Thanks in advance!
According to MSDN(http://msdn.microsoft.com/en-IN/library/b3h1hf19.aspx) a FormatException is thrown when:
s is not in the correct format.
s in your case is SR.ReadLine() which is returning some value that is not recognized as a number format.
At first look it might be because of whitespaces in your file.
Try
SR.ReadLine().Trim()
OR
NumberStyles.AllowLeadingWhite | NumberStyles.AllowTrailingWhite for the number style in the Parse method.