I have a bunch of URIs (Strings) like this:
METRICS.COMPANY.APP1
METRICS.COMPANY.APP1.TOTAL.90DAY
METRICS.COMPANY.APP1.TOTAL.WEEKLY
METRICS.COMPANY.APP1.TOTAL.MONTHLY
METRICS.COMPANY.APP2
METRICS.COMPANY.APP2.TOTAL.90DAY
METRICS.COMPANY.APP2.TOTAL.WEEKLY
METRICS.COMPANY.APP2.TOTAL.MONTHLY
METRICS.BUSINESS.DECISIONS
METRICS.BUSINESS.DECISIONS.MONTHLY
METRICS.BUSINESS.DECISIONS.ANNUALLY
METRICS.EMPLOYEE
METRICS.EMPLOYEE.WEEKLY
Is there a way I can extract the unique "base" URI from each set of similar URIs? That is, I am interested in only getting:
METRICS.COMPANY.APP1
METRICS.COMPANY.APP2
METRICS.BUSINESS.DECISIONS
METRICS.EMPLOYEE
Assuming your data will be ordered, like it is in your example, thus assuming the base will always appear before its children, this is what I came up with:
private static Collection<String> extractBases(String[] nodes) {
Arrays.sort(nodes); // optional, to ensure order
Deque<String> bases = new ArrayDeque<>();
bases.addFirst(nodes[0]);
for (int i = 1; i < nodes.length; i++) {
if (!nodes[i].contains(bases.peekFirst())) { // if it's not a child
bases.addFirst(nodes[i]);
}
}
return bases;
}
You can check a demo with your input here: http://ideone.com/sjEfvc
Related
This question mentions xpaths but it is really not specific to xpaths and really concerns any Java Strings.
I am using Java 8 and have about 40 Strings (public static final String in the class). An example is below:
private static final String employeeID_x = "//input[#id = 'id']";
private static final String employeeName = "//input[#id = 'EmployeeName']";
and there are some more complicated ones like
private static final String age_x = "//div[#id = 'Employee']/div[2]/span[1]";
etc. There are 40 of these. I want to verify all the xpaths so I made an array like
private static final String[] arr = {employeeID_x, employeeName_x, age_x, .....};
then to verify
for (String xp: arr) {
List<WebElement> eles = driver.findElement(By.xpath(xp));
if (eles.size() == 0) {
System.out.println(xp + " does not exist");
}
}
you get the idea. This works, but the error message is
"//div[#id = 'Employee']/div[2]/span[1] does not exist". I guess this is ok but I would rather have it say "age_x does not exist".
I don't know how to print the variable name. I have tried using Class and getFields() but that does not seem to work.
What I have to do is duplicate the array and put each element in quotes like this:
private static final String[] names= {"employeeID_x", "employeeName_x", "age_x", .....};
and then get the number of entries and use
for (int i = 0; i < arr.length; i++) {
String xp = arr[i];
String name = names[i];
List<WebElement> eles = driver.findElements(By.xpath(xp));
if (eles.size() == 0) {
System.out.println(name + " does not exist");
}
}
but as you can see this can get to be a pain. Is there anyway to get the name from xp? Maybe no, as I am afraid when it creates the array it substitutes the value of each string?
And as you can see, this is not specific to xpaths.
I don't know how to print the variable name.
With your current array, you can't (reasonably*) unless you can infer the variable name from the string. This line:
private static final String[] arr = {employeeID_x, employeeName_x, age_x, .....};
...copies the value of employeeID_x, etc., into the array. There is no ongoing link between that value and the variable it came from, just as in this code:
a = b;
...there is no ongoing link between a and b.
Your parallel arrays solution works but as you've said isn't ideal. Using a Map may be slightly better:
private static final Map<String, String> map = new HashMap<>();
static {
map.put("employeeID_x", employeeID_x);
map.put("employeeName_x", "employeeName_x);
// ...
}
Then loop through the map's entries, which give you both the name and value. This still has some repetition (e.g., in each put call you have to type the variable name twice), but it's much better from a maintenance perspective: Dramatically harder to get the two out of sync.
Another option is to use reflection: Your array would be of the names of the variables, and then you'd get the variable's value by using Class#getDeclaredField to get a Field instance for it, then get the value via Field#get. E.g., your array would be:
private static final String[] arr = new String[] { "employeeID_x", "employeeName" /*, ...*/ };
...then:
for (String name : names) {
Field f = YourClass.class.getDeclaredField(name);
String value = (String)f.get(null);
// ...test `value` here, report `name` if there's a problem
}
* "reasonably" - You could have the error code compare the string to every one of your fields and report the match, e.g.
if (theString.equals(employeeID_x)) {
theVariableName = "employeeID_x";
} else if (theString.equals(employeeName_x)) {
theVariableName = "employeeName_x";
} else if (...) {
// ...
...but...blech. :-) (And it assumes that two of these never have the same value.)
I have a repeating structure in my Java class and wanted to present the data as follows:
Peter Black
John Red
I do not know if the structure is right, because if I leave to show the color only, the data is overwritten
public class Test {
public static void main(String[] args) {
List<Person> persons = new ArrayList<>();
String[] names= {"Peter", "John"};
String[] colors= {"Black", "Red"};
for (String name: names) {
Person d = new Person();
d.setName(name);
for (String color: colors) {
d.setColor(color);
}
persons.add(d);
}
for (Person a : persons) {
System.out.println(a.getName() + "-" + a.getColor());
}
}
}
Console:
Peter-Red
John-Red
Instead of using a nested for loop, which is not what you are trying to accomplish, loop through both arrays at the same time.
if (names.length != colors.length) {
// error! not a 1:1 relationship
return;
}
for (int i = 0; i < names.length && i < colors.length; i++) {
String name = names[i], color = colors[i];
Person d = new Person();
d.setName(name);
d.setColor(color);
persons.add(d);
}
I could just do i < names.length, however that will break if both arrays are different sizes, so i < names.length && i < colors.length will make sure i never exceeds either of the two arrays' lengths.
Edit:
I think the real problem here is how you are storing your info. Why are you using two string arrays, instead of a collection containing Person objects?
Stop looping on colors array inside your names loop. A traditional index based loop should help you get the same name and color from each array:
public class Test {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
List<Person> persons = new ArrayList<>();
String[] names= {"Peter", "John"};
String[] colors= {"Black", "Red"};
for (int i=0; i<names.length; i++) {
Person d = new Person();
d.setName(names[i]);
d.setColor(colors[i]);
persons.add(d);
}
for (Person a : persons) {
System.out.println(a.getName() + "-" + a.getColor());
}
}
}
You can use the Enum like
enum Entity {
Peter("Black"),
John("Red");
private final String color;
Entity(String color) {
this.color = color;
}
Notice that your color loop is INSIDE your name loop. So for each name you are setting it's color to the first color then the second color and then you are moving on to the next name.
Your biggest problem is probably the use of the advanced for loop, it doesn't give you an index. If you start with:
for(int i=0;i<names.length;i++)
the solution will probably be obvious (and simplify your code)
(I'd give more but it looks like something you are trying to learn with so I'll try to avoid spoilers)
Re your comment--if you wish to simply create only completely filled out objects, use
for(int i=0;i<Math.min(names.length, colors.length);i++)
If you wish to create partial objects, use Math.max and handle the case inside where either array's length is less than i. It's all business logic code... define what you want to do and do it.
How to handle bad data (Not part of the original problem):
If you want to handle the cases where the arrays are unequal, if you use the "Math.max" solution above, then adding the inside of the loop could look like this:
if(names.length < i)
d.setName(names[i])
if(colors.length < i)
d.setColor(colors[i])
This way there is no exception and you are safely setting values.
But since that leaves your objects invalid, you might be better off not allowing a different number of colors and names from your user. If he enters 3 names, then throw away blank colors and keep re-prompting until you have 3 colors--then stop prompting. It's always safest to catch problems like this as soon as possible.
Another good solution, start with:
if(names.length != colors.length)
throw new IllegalArgumentException("createUsers method must have the same number of names as colors but was called with "+names.length+" names and "+colors.length+" colors")
Ensuring your parameters are correct and throwing an exception if they are not simplifies your code a LOT and is generally a very good practice.
I am busy with a project that extracts data from a xml file and displays it in a word document. I have created a method for this extraction, but I want to simplify it by using an array of methods.
This is just an example of how I test for certain information at the moment:
for (int i = 0; i < nodeMap.getLength(); i++) {
Node node = nodeMap.item(i);
if (node.getNodeName().equalsIgnoreCase("maximumRedeliveries")) {
if (node.getNodeValue().startsWith("{{")) {
retryLogic.setMaximumRedeliveries(extractPropertyName(node.getNodeValue(), propFileLocation));
} else {
retryLogic.setMaximumRedeliveries(node.getNodeValue());
}
}
if (node.getNodeName().equalsIgnoreCase("asyncDelayedRedelivery")) {
if (node.getNodeValue().startsWith("{{")) {
retryLogic.setAsyncDelayedRedelivery(extractPropertyName(node.getNodeValue(), propFileLocation));
} else {
retryLogic.setAsyncDelayedRedelivery(node.getNodeValue());
}
}
}
I am aiming to create an array for the if statement values, for example "maximumRedeliveries" and "asyncDelayedRedelivery" and an array for their corresponding methods, for example setMaximumRedeliveries(),setAsyncDelayedRedelivery(). I am unsure of how to create an array of methods, or if it's even possible?
This problem differs form Java - Creating an array of methods, because I use set methods and don't know how to implement it in that way.
First, ensure that extractPropertyName takes names with and without curly braces, and behaves like this:
String extractOptionalPropertyName(String name, String propFileLocation) {
return name..startsWith("{{") ? extractPropertyName(name, propFileLocation) : name;
}
This moves conditionals from your XML processing code into a helper:
String nodeName = node.getNodeName();
if (nodeName.equalsIgnoreCase("maximumRedeliveries")) {
retryLogic.setMaximumRedeliveries(extractOptionalPropertyName(node.getNodeValue(), propFileLocation));
} else if (nodeName.equalsIgnoreCase("asyncDelayedRedelivery")) {
retryLogic.setAsyncDelayedRedelivery(extractOptionalPropertyName(node.getNodeValue(), propFileLocation));
} ... // and so on
With these changes in place, you can follow the recipe from this other Q&A and make a Map<String,ValSetter> objects, like this:
interface ValSetter {
void set(RetryLogic logic, String val);
}
// The map can be made static in a class
Map<String,ValSetter> setterForName = new HashMap<>();
{ // Initializer block
setterForName.put("maximumredeliveries", new ValSetter() {public void set(RetryLogic logic, String val) { logic.setMaximumRedeliveries(val);}} );
setterForName.put("asyncrelayedredelivery", new ValSetter() {public void set(RetryLogic logic, String val) { logic.setAsyncDelayedRedelivery(val);}} );
}
Now your XML handler could look like this:
String nodeName = node.getNodeName();
ValSetter setter = setterForName.get(nodeName.toLowerCase());
if (setter != null) {
String val = extractOptionalPropertyName(node.getNodeValue(), propFileLocation);
setter.set(retryLogic, val);
} else {
// report an error
}
I am using Java API for KML, JAK, to construct KML files. I would like to be able to delete a feature using its ID, but I have not found a good example of how to do so. Ideally, the code would be "myFolder.deleteFeatureById(theID);", but that is not the case. Is there any better method than the following?
List<Feature> features = myFolder.getFeature();
for(int i=features.size()-1; i>=0; i--)
{
if(features.get(i).getId() == "myId")
{
features.remove(i);
break;
}
}
In Java you need to compare strings using String.equals() method not the logical == operator.
== checks if two things are EXACTLY the same thing, not if they have the same content so some string comparisons can be equal (same string) but test differently with ==.
The following should work.
List<Feature> features = myFolder.getFeature();
for(int i=features.size()-1; i >= 0; i--)
{
if("myId".equals(features.get(i).getId()))
{
features.remove(i);
break;
}
}
Here example code using JAK API that creates two placemarks in a folder then removes one by its id.
final Kml kml = new Kml();
final Folder folder = new Folder();
kml.setFeature(folder);
folder.setName("Folder.kml");
folder.setOpen(true);
final Placemark placemark1 = new Placemark().withId("1")
.withName("Folder object 1 (Placemark)");
folder.getFeature().add(placemark1);
final Placemark placemark2 = new Placemark().withId("2")
.withName("Folder object 2 (Placemark)");
folder.getFeature().add(placemark2);
List<Feature> features = folder.getFeature();
System.out.println(features); // dumps two features
for(int i=features.size()-1; i >= 0; i--)
{
Feature f = features.get(i);
if("1".equals(f.getId()))
{
// this removes feature with id = "1"
features.remove(i);
break;
}
}
System.out.println(features); // folder now only has one item
Related details on this issue:
http://www.javapractices.com/topic/TopicAction.do?Id=18
https://softwareengineering.stackexchange.com/questions/193638/why-didnt-operator-string-value-comparison-make-it-to-java
I want to check to see if two arrays share at least one term in common for my program.
I'm not quite sure what the code is to compare two arrays, but here is what I have so far;
if ((modWikiKeyArray).equals(inputArray[0]))
{
StringBuilder hyperlinkBuilder = new StringBuilder();
for(int i = 0; i < modWikiKeyArray.length; i++)
{
hyperlinkBuilder.append(modWikiKeyArray[i]);
}
}
How would I compare the array modWikiKeyArray to inputArray just to check and see if inputArray[0] is equal to any term inside of modWikiKeyArray?
Arrays.asList lets you build a list backed by an arbitrary array and use convenient Java Collections Framework features like the contains method:
Arrays.asList(oneArray).contains(elementFromAnotherArray)
If you want to see if the arrays have at least one element in common, you could build a HashSet out of one and loop over the other to try to find a common element:
boolean arraysIntersect(Object[] array1, Object[] array2) {
Set array1AsSet = HashSet(Arrays.asList(array1));
for (Object o : array2) {
if (array1AsSet.contains(o)) {
return true;
}
}
return false;
}
You can do the following
for(int i=0;i<modWikiKeyArray.length;i++) {
if(modWikiKeyArray[i].equals(inputArray[0])) {
System.out.println("Match found");
}
}
Note you need to override the equals() method of whatever array you are creating(Class of which array you are creating) .
Going by your code snippet, it looks like you need to check the presence of inputArray[0] only, in which case the following is sufficient:
boolean exists = java.util.Arrays.asList(modWikiKeyArray).contains(inputArray[0]);
Alternatively, you might also want to use ArrayUtils from Apache commons-lang:
boolean exists = ArrayUtils.contains(modWikiKeyArray, inputArray[0]);
However, if I read the text of your question, it seems you want to find if modWikiKeyArray contains at least one item from inputArray. For this you may also use retainAll from the Collections API to perform a list intersecion and see if the intersection list is non-empty.
However, the most primitive is still Aniket's method. However, I will modify it to reduce unnecessary operations:
int i = modWikiKeyArray.length - 1;
MyObject inputElement = inputArray[0];
boolean found = false;
for(; i != 0; i--) {
if(modWikiKeyArray[i].equals(inputElement)) {
found = true;
break;
}
}