selenium xpath query - xpath

var value = selenium.GetXpathCount("//div[contains(#id,'spnPriceDetails')]");
int clickNo = 1;
for (var j = 1; j <= value; j++)
{
if (clickNo == j)
{
selenium.Click("//div[contains(#id,'spnPriceDetails')]");
}
clickNo = clickNo + 1;
}
I have 25 same links on one page I have Identify total number of links using Xpath Count. I Click on First Link But when i try to click on second and thirld link it click on first link every time instead of second and thirld

Your code isn't specifying a later link, it's doing the same search each time, retrieving all 25 that match "//div[contains(#id,'spnPriceDetails')]" and then clicking the first one in the resulting set of matches. You need to add the iterator variable into the search string, like so:
for (var j = 1; j <= value; j++)
{
selenium.Click("(//div[contains(#id,'spnPriceDetails')])[" + j + "]");
}
This way it will click through each value in the list of matches.
Note: I can't remember if xpath will start with 0 index or 1-index. It's supposed to be 1, but if it isn't you may need to start your loop at 0 instead.

I would try to use Position in the xpath expression.
I have created a fluent Xpath library that might be helpful:
The code would be something like:
for (int i = 1; i <= value; i++)
{
selenium.Click(XPathFinder.Find.Tag("div").With.Attribute("id").
Containing("spnPriceDetails").And.Position(i).ToXPathExpression());
}
Some more info on the XPath library can be found here:
http://www.unit-testing.net/CurrentArticle/How-To-Write-XPath-for-Selenium-Tests.html
I guess the plain xpath string way would be:
for (int i = 1; i <= value; i++)
{
selenium.Click(string.Format("//div[contains(#id,'spnPriceDetails') and position()={0}]",i)); }

Related

Method reference giving run time error, where as Supplier Interface works [duplicate]

What does ArrayIndexOutOfBoundsException mean and how do I get rid of it?
Here is a code sample that triggers the exception:
String[] names = { "tom", "bob", "harry" };
for (int i = 0; i <= names.length; i++) {
System.out.println(names[i]);
}
Your first port of call should be the documentation which explains it reasonably clearly:
Thrown to indicate that an array has been accessed with an illegal index. The index is either negative or greater than or equal to the size of the array.
So for example:
int[] array = new int[5];
int boom = array[10]; // Throws the exception
As for how to avoid it... um, don't do that. Be careful with your array indexes.
One problem people sometimes run into is thinking that arrays are 1-indexed, e.g.
int[] array = new int[5];
// ... populate the array here ...
for (int index = 1; index <= array.length; index++)
{
System.out.println(array[index]);
}
That will miss out the first element (index 0) and throw an exception when index is 5. The valid indexes here are 0-4 inclusive. The correct, idiomatic for statement here would be:
for (int index = 0; index < array.length; index++)
(That's assuming you need the index, of course. If you can use the enhanced for loop instead, do so.)
if (index < 0 || index >= array.length) {
// Don't use this index. This is out of bounds (borders, limits, whatever).
} else {
// Yes, you can safely use this index. The index is present in the array.
Object element = array[index];
}
See also:
The Java Tutorials - Language Basics - Arrays
Update: as per your code snippet,
for (int i = 0; i<=name.length; i++) {
The index is inclusive the array's length. This is out of bounds. You need to replace <= by <.
for (int i = 0; i < name.length; i++) {
From this excellent article: ArrayIndexOutOfBoundsException in for loop
To put it briefly:
In the last iteration of
for (int i = 0; i <= name.length; i++) {
i will equal name.length which is an illegal index, since array indices are zero-based.
Your code should read
for (int i = 0; i < name.length; i++)
^
It means that you are trying to access an index of an array which is not valid as it is not in between the bounds.
For example this would initialize a primitive integer array with the upper bound 4.
int intArray[] = new int[5];
Programmers count from zero. So this for example would throw an ArrayIndexOutOfBoundsException as the upper bound is 4 and not 5.
intArray[5];
What causes ArrayIndexOutOfBoundsException?
If you think of a variable as a "box" where you can place a value, then an array is a series of boxes placed next to each other, where the number of boxes is a finite and explicit integer.
Creating an array like this:
final int[] myArray = new int[5]
creates a row of 5 boxes, each holding an int. Each of the boxes has an index, a position in the series of boxes. This index starts at 0 and ends at N-1, where N is the size of the array (the number of boxes).
To retrieve one of the values from this series of boxes, you can refer to it through its index, like this:
myArray[3]
Which will give you the value of the 4th box in the series (since the first box has an index of 0).
An ArrayIndexOutOfBoundsException is caused by trying to retrieve a "box" that does not exist, by passing an index that is higher than the index of the last "box", or negative.
With my running example, these code snippets would produce such an exception:
myArray[5] //tries to retrieve the 6th "box" when there is only 5
myArray[-1] //just makes no sense
myArray[1337] //way to high
How to avoid ArrayIndexOutOfBoundsException
In order to prevent ArrayIndexOutOfBoundsException, there are some key points to consider:
Looping
When looping through an array, always make sure that the index you are retrieving is strictly smaller than the length of the array (the number of boxes). For instance:
for (int i = 0; i < myArray.length; i++) {
Notice the <, never mix a = in there..
You might want to be tempted to do something like this:
for (int i = 1; i <= myArray.length; i++) {
final int someint = myArray[i - 1]
Just don't. Stick to the one above (if you need to use the index) and it will save you a lot of pain.
Where possible, use foreach:
for (int value : myArray) {
This way you won't have to think about indexes at all.
When looping, whatever you do, NEVER change the value of the loop iterator (here: i). The only place this should change value is to keep the loop going. Changing it otherwise is just risking an exception, and is in most cases not necessary.
Retrieval/update
When retrieving an arbitrary element of the array, always check that it is a valid index against the length of the array:
public Integer getArrayElement(final int index) {
if (index < 0 || index >= myArray.length) {
return null; //although I would much prefer an actual exception being thrown when this happens.
}
return myArray[index];
}
To avoid an array index out-of-bounds exception, one should use the enhanced-for statement where and when they can.
The primary motivation (and use case) is when you are iterating and you do not require any complicated iteration steps. You would not be able to use an enhanced-for to move backwards in an array or only iterate on every other element.
You're guaranteed not to run out of elements to iterate over when doing this, and your [corrected] example is easily converted over.
The code below:
String[] name = {"tom", "dick", "harry"};
for(int i = 0; i< name.length; i++) {
System.out.print(name[i] + "\n");
}
...is equivalent to this:
String[] name = {"tom", "dick", "harry"};
for(String firstName : name) {
System.out.println(firstName + "\n");
}
In your code you have accessed the elements from index 0 to the length of the string array. name.length gives the number of string objects in your array of string objects i.e. 3, but you can access only up to index 2 name[2],
because the array can be accessed from index 0 to name.length - 1 where you get name.length number of objects.
Even while using a for loop you have started with index zero and you should end with name.length - 1. In an array a[n] you can access form a[0] to a[n-1].
For example:
String[] a={"str1", "str2", "str3" ..., "strn"};
for(int i=0; i<a.length(); i++)
System.out.println(a[i]);
In your case:
String[] name = {"tom", "dick", "harry"};
for(int i = 0; i<=name.length; i++) {
System.out.print(name[i] +'\n');
}
For your given array the length of the array is 3(i.e. name.length = 3). But as it stores element starting from index 0, it has max index 2.
So, instead of 'i**<=name.length' you should write 'i<**name.length' to avoid 'ArrayIndexOutOfBoundsException'.
So much for this simple question, but I just wanted to highlight a new feature in Java which will avoid all confusions around indexing in arrays even for beginners. Java-8 has abstracted the task of iterating for you.
int[] array = new int[5];
//If you need just the items
Arrays.stream(array).forEach(item -> { println(item); });
//If you need the index as well
IntStream.range(0, array.length).forEach(index -> { println(array[index]); })
What's the benefit? Well, one thing is the readability like English. Second, you need not worry about the ArrayIndexOutOfBoundsException
The most common case I've seen for seemingly mysterious ArrayIndexOutOfBoundsExceptions, i.e. apparently not caused by your own array handling code, is the concurrent use of SimpleDateFormat. Particularly in a servlet or controller:
public class MyController {
SimpleDateFormat dateFormat = new SimpleDateFormat("MM/dd/yyyy");
public void handleRequest(ServletRequest req, ServletResponse res) {
Date date = dateFormat.parse(req.getParameter("date"));
}
}
If two threads enter the SimplateDateFormat.parse() method together you will likely see an ArrayIndexOutOfBoundsException. Note the synchronization section of the class javadoc for SimpleDateFormat.
Make sure there is no place in your code that are accessing thread unsafe classes like SimpleDateFormat in a concurrent manner like in a servlet or controller. Check all instance variables of your servlets and controllers for likely suspects.
You are getting ArrayIndexOutOfBoundsException due to i<=name.length part. name.length return the length of the string name, which is 3. Hence when you try to access name[3], it's illegal and throws an exception.
Resolved code:
String[] name = {"tom", "dick", "harry"};
for(int i = 0; i < name.length; i++) { //use < insteadof <=
System.out.print(name[i] +'\n');
}
It's defined in the Java language specification:
The public final field length, which contains the number of components
of the array. length may be positive or zero.
That's how this type of exception looks when thrown in Eclipse. The number in red signifies the index you tried to access. So the code would look like this:
myArray[5]
The error is thrown when you try to access an index which doesn't exist in that array. If an array has a length of 3,
int[] intArray = new int[3];
then the only valid indexes are:
intArray[0]
intArray[1]
intArray[2]
If an array has a length of 1,
int[] intArray = new int[1];
then the only valid index is:
intArray[0]
Any integer equal to the length of the array, or bigger than it: is out of bounds.
Any integer less than 0: is out of bounds;
P.S.: If you look to have a better understanding of arrays and do some practical exercises, there's a video here: tutorial on arrays in Java
For multidimensional arrays, it can be tricky to make sure you access the length property of the right dimension. Take the following code for example:
int [][][] a = new int [2][3][4];
for(int i = 0; i < a.length; i++){
for(int j = 0; j < a[i].length; j++){
for(int k = 0; k < a[j].length; k++){
System.out.print(a[i][j][k]);
}
System.out.println();
}
System.out.println();
}
Each dimension has a different length, so the subtle bug is that the middle and inner loops use the length property of the same dimension (because a[i].length is the same as a[j].length).
Instead, the inner loop should use a[i][j].length (or a[0][0].length, for simplicity).
For any array of length n, elements of the array will have an index from 0 to n-1.
If your program is trying to access any element (or memory) having array index greater than n-1, then Java will throw ArrayIndexOutOfBoundsException
So here are two solutions that we can use in a program
Maintaining count:
for(int count = 0; count < array.length; count++) {
System.out.println(array[count]);
}
Or some other looping statement like
int count = 0;
while(count < array.length) {
System.out.println(array[count]);
count++;
}
A better way go with a for each loop, in this method a programmer has no need to bother about the number of elements in the array.
for(String str : array) {
System.out.println(str);
}
ArrayIndexOutOfBoundsException whenever this exception is coming it mean you are trying to use an index of array which is out of its bounds or in lay man terms you are requesting more than than you have initialised.
To prevent this always make sure that you are not requesting a index which is not present in array i.e. if array length is 10 then your index must range between 0 to 9
ArrayIndexOutOfBounds means you are trying to index a position within an array that is not allocated.
In this case:
String[] name = { "tom", "dick", "harry" };
for (int i = 0; i <= name.length; i++) {
System.out.println(name[i]);
}
name.length is 3 since the array has been defined with 3 String objects.
When accessing the contents of an array, position starts from 0. Since there are 3 items, it would mean name[0]="tom", name[1]="dick" and name[2]="harry
When you loop, since i can be less than or equal to name.length, you are trying to access name[3] which is not available.
To get around this...
In your for loop, you can do i < name.length. This would prevent looping to name[3] and would instead stop at name[2]
for(int i = 0; i<name.length; i++)
Use a for each loop
String[] name = { "tom", "dick", "harry" };
for(String n : name) {
System.out.println(n);
}
Use list.forEach(Consumer action) (requires Java8)
String[] name = { "tom", "dick", "harry" };
Arrays.asList(name).forEach(System.out::println);
Convert array to stream - this is a good option if you want to perform additional 'operations' to your array e.g. filter, transform the text, convert to a map etc (requires Java8)
String[] name = { "tom", "dick", "harry" };
--- Arrays.asList(name).stream().forEach(System.out::println);
--- Stream.of(name).forEach(System.out::println);
ArrayIndexOutOfBoundsException means that you are trying to access an index of the array that does not exist or out of the bound of this array. Array indexes start from 0 and end at length - 1.
In your case
for(int i = 0; i<=name.length; i++) {
System.out.print(name[i] +'\n'); // i goes from 0 to length, Not correct
}
ArrayIndexOutOfBoundsException happens when you are trying to access
the name.length indexed element which does not exist (array index ends at length -1). just replacing <= with < would solve this problem.
for(int i = 0; i < name.length; i++) {
System.out.print(name[i] +'\n'); // i goes from 0 to length - 1, Correct
}
According to your Code :
String[] name = {"tom", "dick", "harry"};
for(int i = 0; i<=name.length; i++) {
System.out.print(name[i] +'\n');
}
If You check
System.out.print(name.length);
you will get 3;
that mean your name length is 3
your loop is running from 0 to 3
which should be running either "0 to 2" or "1 to 3"
Answer
String[] name = {"tom", "dick", "harry"};
for(int i = 0; i<name.length; i++) {
System.out.print(name[i] +'\n');
}
Each item in an array is called an element, and each element is accessed by its numerical index. As shown in the preceding illustration, numbering begins with 0. The 9th element, for example, would therefore be accessed at index 8.
IndexOutOfBoundsException is thrown to indicate that an index of some sort (such as to an array, to a string, or to a vector) is out of range.
Any array X, can be accessed from [0 to (X.length - 1)]
I see all the answers here explaining how to work with arrays and how to avoid the index out of bounds exceptions. I personally avoid arrays at all costs. I use the Collections classes, which avoids all the silliness of having to deal with array indices entirely. The looping constructs work beautifully with collections supporting code that is both easier to write, understand and maintain.
If you use an array's length to control iteration of a for loop, always remember that the index of the first item in an array is 0. So the index of the last element in an array is one less than the array's length.
ArrayIndexOutOfBoundsException name itself explains that If you trying to access the value at the index which is out of the scope of Array size then such kind of exception occur.
In your case, You can just remove equal sign from your for loop.
for(int i = 0; i<name.length; i++)
The better option is to iterate an array:
for(String i : name )
System.out.println(i);
This error is occurs at runs loop overlimit times.Let's consider simple example like this,
class demo{
public static void main(String a[]){
int[] numberArray={4,8,2,3,89,5};
int i;
for(i=0;i<numberArray.length;i++){
System.out.print(numberArray[i+1]+" ");
}
}
At first, I have initialized an array as 'numberArray'. then , some array elements are printed using for loop. When loop is running 'i' time , print the (numberArray[i+1] element..(when i value is 1, numberArray[i+1] element is printed.)..Suppose that, when i=(numberArray.length-2), last element of array is printed..When 'i' value goes to (numberArray.length-1) , no value for printing..In that point , 'ArrayIndexOutOfBoundsException' is occur.I hope to you could get idea.thank you !
You can use Optional in functional style to avoid NullPointerException and ArrayIndexOutOfBoundsException :
String[] array = new String[]{"aaa", null, "ccc"};
for (int i = 0; i < 4; i++) {
String result = Optional.ofNullable(array.length > i ? array[i] : null)
.map(x -> x.toUpperCase()) //some operation here
.orElse("NO_DATA");
System.out.println(result);
}
Output:
AAA
NO_DATA
CCC
NO_DATA
In most of the programming language indexes is start from 0.So you must have to write i<names.length or i<=names.length-1 instead of i<=names.length.
You could not iterate or store more data than the length of your array. In this case you could do like this:
for (int i = 0; i <= name.length - 1; i++) {
// ....
}
Or this:
for (int i = 0; i < name.length; i++) {
// ...
}

handsontable's subproject rulejs: how to get the calculated value of a formula cell?

rulejs subproject of handsontable is great. But I can't find anything that emulates the "paste special" of spreadsheets. So, if I write
afterOnCellMouseDown: function(r, c) {
var x = hotdata[c['row']][c['col']];
document.getElementById("valorCelCorrente").innerHTML = x;}
I get the formula, not the calculated value that the cell is displaying. Same happens with a manual copy & paste.
A fiddle with example: https://jsfiddle.net/zota/j2a04w83/3/
Any clue? Thanks a lot
Julio
I had the same issue, but solved it with the help of this question.
Firstly you can use hot.plugin.helper.cellValue('CELL REF') to get the actual value, but when using getData() you're looking at the whole set. To solve this problem I basically iterated through the array replacing any formula cells with the value (I only needed columns up until 'K'):
var aCols = ['A','B','C','D','E','F','G','H','I','J','K'];
var data = hot.getData();
for (i = 0; i < data.length; i++){
for(j = 0; j < data[i].length; j++){
if(data[i][j].toString().indexOf('=') > -1){
data[i][j] = hot.plugin.helper.cellValue (aCols[j] + (i+1));
}
}
}

Delay code execution in VCL Forms Application

Need to animate a sorting algorithm, with source code line by line visualization.
INTRO:
For the begining, there is a FORM (see it in the picture attached). On top of that form is displayed a dinamicaly created array of Edit components, containing the array to sort.
A little below, on the right is placed a Memo component, containing the algorithm. At the left of each line of that algorithm, dinamicaly is placed a Label, that indicates the line number in algorithm.
The idea is to highlight line by colouring that label, where is the execution at the moment. Sorting starts when "Start" button is clicked. The action for it is following:
int n = 10;
bool swapped = true; hl(1);
int j = 0; hl(2);
int tmp; hl(3);
while (swapped) { hl(4);
swapped = false; hl(5);
j++; hl(6);
for (int i = 0; i < n - j; i++) { hl(7);
if (arr[i] > arr[i + 1]) { hl(8);
tmp = arr[i]; hl(9);
arr[i] = arr[i + 1]; hl(10);
arr[i + 1] = tmp; hl(11);
swapped = true; hl(12);
} hl(13);
} hl(14);
} hl(15);
The hl function must colour labels and pause execution by using Sleep() function
void TForm2::hl(int l)
{
for (int i = 0; i < 24; i++) {
Form2->lines[i]->Font->Color = clGray;
}
Form2->lines[l-1]->Font->Color = clRed;
Sleep(300);
}
PROBLEM:
Code execution is pausing (sleep function works properly), but the labels are still gray, with no visible changes, except the last one, when event finishes. The 15th line is red.
QUESTION:
Can anybody tell me, where I'm wrong, and how to do it right?
http://i.stack.imgur.com/crGyC.jpg
You need to allow the paint message to be processed in order to visually update the display. You can do that with either the Refresh or Update procedures:
Form2->Lines[l-1]->Font->Color = clGray;
Form2->Update(); // or Form2->Refresh();

OpenCV image pointer not working as expected

So I have to do some operations on part of an image. The operation is not relevant (i dont change this code at all), but the way i create the pointer changes the results i get. I dont understand why that happens.
Why does this code gets the result I want:
for(int row = 0; row < 70; ++row) {
for(int col = 48; col < 208; ++col) {
uchar* p = c.ptr(row+col);
*p = (1-circuloBinario.at<unsigned char>(row,col-48))*(*p) + circuloBinario.at<unsigned char>(row,col-48)*limite;
}
}
And this one doesnt?
for(int row = 0; row < 70; ++row) {
uchar* p = c.ptr(row+48);
for(int col = 48; col < 208; ++col) {
*p = (1-circuloBinario.at<unsigned char>(row,col-48))*(*p) + circuloBinario.at<unsigned char>(row,col-48)*limite;
p++;
}
}
By the way, I dont get any errors with the second code, the problem is that the result I get is not what I expect (it starts modifying the image from a row bigger than 0 and starts from column 0 instead of 48).
Thanks.
Mat::ptr returns a pointer to the specified matrix row.
See the documentation here: http://docs.opencv.org/modules/core/doc/basic_structures.html#mat-ptr
So neither c.ptr(row+col) nor c.ptr(row+48) make sense because you should only be passing a row index to the ptr function.
The way you use Mat::pt is apparently incorrect, as mentioned by M456.
If you want to modify the value of some elements of the matrix, why don't you use the following syntax?
c.at<element_type>(row, col) = new_value;

Algorithm to find first index where strings are different?

I've got a collection of strings, and I need to know the first index where they all differ. I can think of two ways to do this: (the following pseudo code is just off the top of my head and may be heavily bug-laden)
First Way:
var minLength = [go through all strings finding min length];
var set = new set()
for(i=0;i<minlength;i++)
{
for(str in strings)
{
var substring = str.substring(0,i);
if(set.contains(substring))
break; // not all different yet, increment i
set.add(substring)
}
set.clear(); // prepare for next length of substring
}
This strikes me as gross because of the use of a set data structure where it seems like one should not be needed.
Second Way:
var minLength = [go through all strings finding min length];
strings.sort();
for(i=0;i<minlength;i++)
{
boolean done = true;
char last = null;
for(str in strings)
{
char c = str[i];
if(c == last)
{
// not all different yet, increment i
done = false;
break;
}
last = c;
}
if(done)
return i;
}
But it annoys me that I have to run the sort first, because the sorting algorithm, by its very nature, has access to the information that I'm looking for.
Surely there must be a more efficient way than what I have listed above. Eventually I'd like to abstract it out to any type of array, but that will be trivial and it's simpler to think of it as a string problem.
Any help?
**UPDATE: I apparently didn't explain myself very well. If my strings are ["apple", "banana", "cucumber", "banking"], I want the function to return 3, because there were two strings ("banana" and "banking") that matched through index 0, 1, and 2, so 3 is the first index where they are all unique.
As Daniel mentioned below, a better way to state my needs is that: "I want to find index i where calling substring(0,i) on all my strings will result in all unique values."**
This is untested, but here's my attempt. (I may be making it more complicated than I have to, but I think it's a different way to look at it.)
The basic idea is to compile groups of items that match at the first element, then find the max unique index for each group, checking elements at each successive index.
int FirstUniqueIndex<T>(IEnumerable<IEnumerable<T>> myArrayCollection)
{
//just an overload so you don't have to specify index 0 all the time
return FirstUniqueIndex(myArrayCollection, 0);
}
int FirstUniqueIndex<T>(IEnumerable<IEnumerable<T>> myArrayCollection, int StartIndex)
{
/* Group the current collection by the element at StartIndex, and
* return a collection of these groups. Additionally, we're only interested
* in the groups with more than one element, so only get those.*/
var groupsWithMatches = from var item in myArrayCollection //for each item in the collection (called "item")
where item.Length > StartIndex //that are long enough
group by item[StartIndex] into g //group them by the element at StartIndex, and call the group "g"
where g.Skip(1).Any() //only want groups with more than one element
select g; //add the group to the collection
/* Now "groupsWithMatches" is an enumeration of groups of inner matches of
* your original arrays. Let's process them... */
if(groupsWithMatches.Any())
//some matches were found - check the next index for each group
//(get the maximum unique index of all the matched groups)
return groupsWithMatches.Max(group => FirstUniqueIndex(group, StartIndex + 1));
else
//no matches found, all unique at this index
return StartIndex;
}
And for the non-LINQ version of the above (I'll change it to use a List collection, but any collection will do). I'll even remove the lambda. Again untested, so try not to aim sharp implements in my direction.
int FirstUniqueIndex<T>(List<List<T>> myArrayCollection, int StartIndex)
{
/* Group the current collection by the element at StartIndex, and
* return a collection of these groups. Additionally, we're only interested
* in the groups with more than one element, so only get those.*/
Dictionary<T, List<List<T>>> groupsWithMatches = new Dictionary<T, List<List<T>>>();
//group all the items by the element at StartIndex
foreach(var item in myArrayCollection)
{
if(item.Count > StartIndex)
{
List<List<T>> group;
if(!groups.TryGetValue(item[StartIndex], out group))
{
//new group, so make it first
group = new List<List<T>>();
groups.Add(item[StartIndex], group);
}
group.Add(Item);
}
}
/* Now "groups" is an enumeration of groups of inner matches of
* your original arrays. Let's get the groups with more than one item. */
List<List<List<T>>> groupsWithMatches = new List<List<List<T>>>(groups.Count);
foreach(List<List<T> group in groupsWithMatches)
{
if(group.Count > 1)
groupsWithMatches.Add(group);
}
if(groupsWithMatches.Count > 0)
{
//some matches were found - check the next index for each group
//(get the maximum unique index of all the matched groups)
int max = -1;
foreach(List<List<T>> group in groupsWithMatches)
{
int index = FirstUniqueIndex(group, StartIndex + 1);
max = index > max ? index : max;
}
return max;
}
else
{
//no matches found, all unique at this index
return StartIndex;
}
}
have you looked at a Patricia trie? (Java implementation available on google code)
Build the trie, then traverse the data structure to find the maximum string position of all the internal nodes (black dots in the function above).
This seems like it should be an O(n) operation. I'm not sure whether your set implementation is O(n) or not -- it "smells" like O(n2) but I'm not sure.
Use the set as you proposed, that's exactly the right thing to do.
You should be able to do this without sorting, and with only looking at each character in each string once in the worst case.
here is a ruby script that puts the index to the console:
mystrings = ["apple", "banana", "cucumber", "banking"]
minlength = getMinLengthString(mystrings) #not defined here
char_set = {}
(0..minlength).each do |char_index|
char_set[mystrings[0][char_index].chr] = 1
(1..mystrings.length).each do |string_index|
comparing_char = mystrings[string_index][char_index].chr
break if char_set[comparing_char]
if string_index == (mystrings.length - 1) then
puts string_index
exit
else
char_set[comparing_char] = 1
end
end
char_set.clear
end
puts minlength
the result is 3.
Here's the same general snippet in C#, if it is more legible for you:
string[] mystrings = { "apple", "banana", "cucumber", "banking" };
//defined elsewhere...
int minlength = GetMinStringLengthFromStringArray(mystrings);
Dictionary<char, int> charSet = new Dictionary<char, int>();
for (int char_index = 0; char_index < minlength; char_index++)
{
charSet.Add(mystrings[0][char_index], 1);
for (int string_index = 1; string_index < mystrings.Length; string_index++)
{
char comparing_char = mystrings[string_index][char_index];
if (charSet.ContainsKey(comparing_char))
{
break;
}
else
{
if (string_index == mystrings.Length - 1)
{
Console.Out.WriteLine("Index is: " + string_index.ToString());
return;
}
else
{
charSet.Add(comparing_char, 1);
}
}
}
charSet.Clear();
}
Console.Out.WriteLine("Index is: " + minlength.ToString());
int i = 0;
while(true)
{
Set set = new Set();
for(int j = 0; j < strings.length; j++)
{
if(i >= strings[j].length) return i;
String chr = strings[j].charAt(i);
if(set.hasElement(chr))
break;
else
set.addElement(chr);
}
if(set.size() == strings.length)
return i;
i++;
}
Gotta check preconditions first.
EDIT: Using a set now. Changed langauge.
Here's my solution in Python:
words = ["apple", "banana", "cucumber", "banking"]
for i in range(len(min(words))):
d = defaultdict(int)
for word in words:
d[word[i]] += 1
if max(d.values()) == 1:
return i
I didn't write in anything to handle the case where no minimum index is found by the time you reach the end of the shortest word, but I'm sure you get the idea.

Resources