I've been messing around with Jsoup lately. My friend loves to buy gold for Diablo, so I thought I'd make him a little program that will grab the prices from various websites and present them to him, so he can spend as little money as possible. Usually, I can grab the price like this;
Document Fasteve;
try {
Fasteve = Jsoup.connect("http://www.fasteve.com/diablo-3/Gold/?st=US(Normal)").get();
Elements Price = Fasteve.select("table[class=table_2] tr:eq(5) td:eq(1)");
System.out.println("http://www.fasteve.com/diablo-3/Gold/?st=US(Normal)");
System.out.println("1000M Gold = " + Price.text());
} catch (IOException e) {
e.printStackTrace();
}
However I can't use that method. Nor can I use the method where you state the tr and td you are grabbing from because.. for this site, all the tr's have the same class so I can't call
Elements Price = Fasteve.select("table[class=table] tr[class=row] td:[class=column]");
Any thoughts as to how I can grab that value? (64.37)
Thanks once again, Stackoverflow.
Consider
Creating a class that holds the td1 String and the td2 or price String, say let's call it DiabloGoldRow or some-such.
creating an Collection of this class, say, ArrayList<DiabloGoldRow>, or if you want to be able quickly get information based on the td1 String, a HashMap<String, DiabloGoldRow>.
Then using JSoup to isolate the information in the table, and then iterate through it in a for loop, creating instances of DiabloGoldRow objects and putting them into the ArrayList or other collection (i.e., HashMap).
I'll leave the details of the code as an exercise for the student.
Edit
You ask,
Why do I need to create a separate class to hold the variables?
Because you need to hold the two pieces of information held on each row close together and may need to search on one to obtain the other. It's a lot cleaner to do it this way than to use 2D arrays or parallel arrays. What is your objection towards doing this?
Edit 2
You state,
I am not opposed to anything. I'm simply wondering how that will help me grab the values I need. My question was using the methods I normally do, I cannot grab the data I want to. I was simply looking for a different syntax to grab the specified data.
Again, one way you can do this with a for loop. Simply loop through the rows of the table:
Elements eles = doc.select("table tr");
for (int i = 0; i < eles.size(); i++) {
Elements rowEles = eles.get(i).select("form");
Elements goldEles = rowEles.select("[name=gold]");
String goldValue = goldEles.attr("value");
Elements priceEles = rowEles.select("[name=price]");
String priceValue = priceEles.attr("value");
System.out.printf("%-7s: %-5s%n", goldValue, priceValue);
}
Related
I need some help here - I want to do a little card game for learning reasons.
I have a class (Tree/Baum) and an ArrayList "TreeList" of several trees of object Tree.
Now I want to load different random objects of that class in a new ArraList called "PlayersHand".
To do this I have created a for-loop with a tmpObj of type Tree which loads a random index from ArrayList"TreeList" of all Trees. After that it modifies some values of the tmpObj by random (f.e. tree height). Then it adds this whole tmpObject to the ArrayList "PlayersHand".
The Problem is, that when I read out the values of the objects inside PlayersHand the modified values don't show the right way. They always show the last value of the treetype, so f.e. if the last tree of type ACER was 20m high, all the previous trees of type ACER are 20m high too.
It seems like all the objects in the ArrayList "playersHand" are just pointers to the different objects of ArrayList "TreeList".
But why ? And how can I fix it?
The code where the objects are copied:
//"PlayersHand get cards
for(int i=0;i<amountOfCards;i++)
{
int randomNr = (int)(Math.random()* TreeList.size());
Tree tmpTree = TreeList.get(randomNr);
tmpTree.modifyValues();
playersHand.add(tmpTree);
for(int y=0; y<playersHand.size();y++)
{
Tree tmpTree2 = playersHand.get(y);
System.out.println(" - different values of that object shown here - ");
}
}
Edit: Previously I had a more complex scenario. I tried to reduce complexity for better understanding.
I solved it - If someone has the same issue :
You have to use a copy constructor.
I have a string that needs to be compared to the names that are on the website. So the first thing I do is get the number of rows (because some arrays have more or fewer than 2 people in them) and then put that size into an int. String[] names come from the names that selenium is supposed to find when it goes to the website to execute this statement assertTrue(assertion.getText().contains(names[i-1])); The problem is: if the names do not appear in the order in which they appear in the array it breaks. In other words, if Mick Jagger is in li[1] and Keith Richards is in li[2], everything runs as expected. But if Keith Richards appears in li[1] it breaks. Furthermore, I am supposed to use the assertTrue command to do this. I have tried sorting, pushing whats on the web into a new ArrayList and I keep getting errors. Anyone know a good way to ensure the order isn't important and still use the assertTrue command?
Thanks,
Scott
WebElement assertion = null;
List<WebElement> assignees = driver.findElements(By.xpath(".//*[#id='assignee']/li"));
int count = assignees.size();
String[] names = {"Mick", "Keith"};
for (int i = 1; i < count; i++)
{
assertion = driver.findElement(By.xpath(".//*[#id='assignee']/li["+i+"]"));
assertTrue(assertion.getText().contains(names[i-1]));
If names represents the full string, you can just flip it. Make sure the text in your assertion (probably should be named something like assignee instead of assertion) is contained in your collection:
assertTrue(Arrays.asList(names).contains(assertion.getText());
Let me know if this won't work because a name is actually a subset of the text in assertion and I'll adjust the answer.
If they don't exactly match (which you have indicated they don't), you could use linq in c# to match this. Since you're using java you can use an additional loop. There may be a more efficient way to do this in java that I'm not aware of.
String assigneeText = assertion.getText();
boolean nameFound = false;
for(String name: names)
{
nameFound = assigneeText.contains(name);
if(nameFound)
{
break;
}
}
assertTrue(nameFound, "None of the expected names were found in the following assignee text: " + assigneeText);
I need to: 1) create long list of BitmapFields and 2) add them to the screen. Since list is long I want to use some short automated method like Loop or similar:
while (i < 1000)
{
i = i + 1;
myBitmapField[i].setBitmap(Bitmap.getBitmapResource("picture" + i+ ".png"));
myVerticalFieldManager.add(_myBitmapField[i]);
}
But it seems that I cannot assign a index i to a name of BitmapField myBitmapField[i], only to a name of the file itself.
So how can I create a long list of BitmapFields ? Can i use List, Array, HashMap, or HashSet for this purpose? An example welcome. Thanks a lot! (Blackberry, Java)
If you're getting that error, that just means that myBitmapField isn't declared as an array type. You'll want to declare it as an array, e.g:
BitmapField[] myBitmapField = new BitmapField[1000];
for (int i = 0; i < 1000; i++) {
myBitmapField[i] = new BitmapField();
}
You could in principle use any of the data types you listed, though only an array can be indexed with the [...] syntax. You just have to change the declaration initialization to use whatever data type you want. And if you use a type that doesn't support indexes you'll have to change your index to use the .get method on the data type you choose. But I'm not sure why you'd want to use anything other than an array...
And at that point you might as well combine the above loop with your existing loop, so that you only have one loop.
Also, if you have 1000 images being displayed, you will probably have horrible performance. BlackBerry has trouble dealing with 1000 fields of any type in a list, and images can be fairly heavyweight. It may even take so long to load on some devices that the BlackBerry will think your app is hanging and terminate it. Not to mention that it isn't very good from a UI perspective to have so many items on a small mobile screen, since no user would be able to navigate to all of them in a reasonable timeframe.
I tried your way, doesn't seem to for for me either. try this:
private pics = new Vector();
for(int i = 0; i < 1000; i++{
BitmapField temp = new BitmapField();
pics.addElement(temp);
((BitmapField)pics.elementAt(i)).setBitmap(Bitmap.getBitmapResource("picture" + i + ".png"));
add((BitmapField)pics.elementAt(i));
}
Also i agree with #Ted about the 1000 fields. good luck, let us know.
I need to sort an array based on the positions held in another array.
What I have works, but it is kinda slow, is there a faster/better way to implement this?
2 Parts:
Part1
int i = mArrayName.size();
int temp = 0;
for(int j=0;j<i;j++){
temp = mArrayPosition.get(j);
mArrayName.set(temp, mArrayNameOriginal.get(j));
}
In this part, mArrayPosition is the position I would like the mArrayName to be in.
Ex.
input:
mArrayName= (one, two, three)
mArrayPosition = (2,0,1)
output:
mArrayName= (three, one two)
Part 2
int k=0;
int j=0;
do{
if(mArrayName.get(k)!=mArrayNameOriginal.get(j)){
j++;
}else{
mArrayIdNewOrder.set(k, mArrayId.get(j));
k++;
j=0;
}
}while(k < mArrayName.size());
}
In this part, mArrayName is the reordered name array, mArrayNameOriginal is the original name array.
Ex.
mArrayName = (three, one, two)
mArrayNameOriginal = (one, two, three)
Now I want to compare these two arrays, find which entries are equal and relate that to a new array that has their rowId number in it.
Ex.
input:
mArrayId = (001,002,003)
output:
mArrayIdNewOrder = (003,001,002)
So then I will have mArrayIdNewOrder id's matching up with the correct names in mArrayName.
Like I said these methods work, but is there a faster/better way to do it? I tried looking at Arrays.sort and comparators but they only seem to sort alphabetically or numerically. I saw something like I can create my own rules inside the comparator but it would probably end up being similar to what I already have.
Sorry for the confusing question. I'll try to clear up any ambiguities if needed.
The best performance read I've found is Android's Designing For Performance doc. You are violating a couple of the "Android way" style of doing things that will help you.
You are using multiple internal getters inside each loop for what looks like a simple value. Redo this by accessing the fields directly.
For extra credit, post your performance comparison results! I'd love to see em!
You could use some form of tuple, some class to hold both id and name. You'll just to have a java.util.Comparator that compares it accordingly, both elements will move together and your code will be cleaner.
This data structure might be convenient for the rest of your program... if not, just take things off it again and you're done.
If your order indexes are compact, i.e. from index 0 to size - 1, then just use an array and create the updated list afterwards? About something like
MyArray[] array = new MyArray[size];
for(int j=0;j< size;j++) {
array[ mArrayPosition.get(j) ] = mArrayName.get(j);
}
// create ArrayList from array
I have a combobox which stores "Computer ,Code:21","History ,Code:31" and also the number of items can be changed.but when I write this code for getting its items:
List<String> bIHELessons = new ArrayList<String>();
for (int i=0;i<jComboBox1.getItemCount();i++) {
String lessons = (String) jComboBox1.getItemAt(i);
if (lessons != null&& lessons.trim().length()!=0) {
bIHELessons.add(lessons);
System.out.println(bIHELessons.toString());
}
}
it will show these sentences in the console:
[Computer,Code=21]
[Computer,Code=21, History,Code:31]
Because you are appending to the list with bIHELessons.add(..). Each subsequent call adds on to the already printed string.
If you want to still add to the ArrayList and print the current item that is in the ArrayList, then use System.out.println(bIHELessons.get(i)); rather than using what you are now. I also don't think you need to use toString() because your objects are already in the type string.
Change System.out.println(bIHELessons.toString()); to System.out.println(lessons); if you only want to print the string you are currently iterating on.
From what I can see your code is doing what it should be doing. Are you wanting to know why you are seeing all items repeated with each additional call to the print screen?
That is happening because the toString() method of the List is putting all the items in the list into a single string.
I don't think the problem is with JComboBox but rather with your expectations. System.out.println(bIHELessons.toString()); will print out the entire contents of the bIHELessons ArrayList. Since you're adding a new String to the ArrayList on each iteration, it's logical that your System.out.println(bIHELessons.toString()); would show a progressive accumulation of content.
Your question isn't clear but you may consider moving the System.out.println outside of your loop and determining if that's what you're looking for.
You are printing out the ToString() representation of your entire list. If you want to print out the object you could just print out the lessons variable instead.