Problem
I need to change all list items during a loop. Is it possible?
Code
List<WebElement> elements = driver.findElements(By.xpath('//*[#id="id1"]//tr[td/a]'))
elements.eachWithIndex { element, index ->
...
if(...) {
...
i = index+1
elements = driver.findElements(By.xpath('//*[#id="id1"]//tr[td/a][position()>' + i + ']')) // new list content which must be use by loop
}
}
However, new list is not used by the loop.
Can you help and explain me why?
Thanks
Regards
EDIT 1
I need to retrieve element everytime.
List<WebElement> elements = driver.findElements(By.xpath('//*[#id="dzA26"]//tr[td/a]'))
for(int i = 1; i <= elements.size(); i++) {
WebElement element = driver.findElement(By.xpath('//*[#id="dzA26"]//tr[td/a][' + i + ']'))
...
}
So first of all while iterating over a List, changing or removing elements is not safe to do. It can be possible, but you should avoid it.
That's because you are trying to change the element it is currently iterating at. So the Iterator behind the '.each' closure gets confused and doesn't know where to go on after the current iteration.
If you have to change all elements with the same operation, you could use the List.collect() closure provided by groovy, which will return whatever you like into a new List.
e.g.:
List<WebElement> elements = elements.collect { element ->
return element.doSomething()
}
Edit 1
After your update there is a new Problem, because it seems like you always want to update all Elements int the List.
So why don't you create the List inside the Loop, fill it, and use it, then go to the next iteration.
e.g.:
for(int i = 0;i < threshold; i++) {
List<WebElement> elements = useMethodToRetrieveElementsFori(i);
elements.each {
// Do whatever has to be done with this element.
}
}
Or after looking at it a little longer, it seems obvious to use code reflection at that point. Because you want to dig deeper into the WebElements, you should call a method that calls itself if it needs to go one step further. With your idea, you'd be stuck in an endless loop.
Or we are missing the the whole point of the question.
Related
I am trying to create an app that let's you type in what you want to eat and drink. It calculates all of that and then when you press the print button, I want it to count how often each item's in the list and give it back like this:
"9x Juice /n
5x Steaks /n
4x Salads"
The drinks and foods are objects in the new class Edibles:
class Edibles(val name: String, val price: Double):Serializable {
}
I track all of the objects in the MutableList order and can access the different members of the list and their attributes, but when I try to removeAll duplicates in my list, android studio complains and I don't know how to fix it.
My try to calculate how many members are in the list order:
var totalOrder = ""
for(i in order){
var number = order.count {it == order[0]}
totalOrder = totalOrder + "$number" + "x" + order[0].name + "\n"
order.removeAll(order[0])
}
The problem as far as I saw so far is, that Edibles doesn't have the interface Collection and when I try to implement that, it wants me to override a bunch of functions where I don't know what to do with it...
If anyone has an explanation or even a fix or an idea on how to do it differently, I would be very grateful
removeAll is meant to take a list or a predicate, not a single element. If you convert your element to a predicate checking for equality, it will remove all elements equal to that one.
order.removeAll { it == order[0] }
However, you'll also need to remember rule number one of iteration: Never delete while iterating. So what you really want to do is accumulate all of the "deletion" candidates into a list and then delete them after-the-fact.
In fact, what you're doing here can be done without mutating the list at all, using a built-in list combinator called groupBy.
var totalOrder = ""
for (entry in order.groupBy { it }) {
val item = entry.key
val count = entry.value.size
totalOrder += "${count}x${item.name}\n"
}
You're not allowed to mutate a collection while iterating it in a for loop anyway. One way to remove duplicates would be to create a temporary MutableSet and compare each item to it in a removeAll operation. removeAll takes a lambda predicate that is called on each item and the Boolean you return from the predicate. When you call add on a MutableSet, it returns a Boolean to tell you if the item already was in the set, so you can remove duplicates with the following.
Assuming you just want to compare names of items to determine if they are duplicates, you can create a MutableSet<String>.
with (mutableSetOf<String>()) {
order.removeAll { add(it.name) }
}
The DoCollision function is a callback function which is checking for collisions every frame by iterating over a collider list.
void Collision::DoCollisions(Game *game){
for (ColliderList::const_iterator colliderAIt = colliders_.begin();
colliderAIt != colliders_.end();
colliderAIt++)
{
ColliderList::const_iterator colliderBIt = colliderAIt;
for (++colliderBIt; colliderBIt != colliders_.end(); ++colliderBIt)
{
Collider *colliderA = *colliderAIt;
Collider *colliderB = *colliderBIt;
if (CollisionTest(colliderA, colliderB))
{
game->DoCollision(colliderA->entity, colliderB->entity);
}
}
}
if collision test passes for any two game entities, game entity(Base class for all game objects) class destructor invoke function DestroyCollider which removes the respective collider elements from the list.
void Collision::DestroyCollider(Collider *collider){
colliders_.remove_if(std::bind1st((std::equal_to<Collider *>()), collider));
delete collider }
You're removing the element of a list that the iterator points to. That invalidates the iterator, meaning you're not allowed to use it anymore.
A typical remove loop for a list or vector looks like this:
for (auto iterator = list.begin(); iterator != list.end(); ) {
if (should_remove(iterator)) {
iterator = list.erase(iterator);
} else {
++iterator;
}
}
Note how, if an element is to be removed, the iterator is not incremented, but instead replaced with the result of the erase call.
You will have to find a way to refactor your code to match this pattern. This is complicated because your condition is deep within the collision function, but you can do either that (which has the advantage of making your code more efficient by getting rid of the linear search, by the way), or you can, instead of immediately removing the elements, collect them in a separate list, and then remove them after you're done iterating over the main list.
Or you can turn colliders_ into an intrusive list (e.g. from Boost.Intrusive, or hand-written). Intrusive lists are very good for situations like yours.
There is an issue with enumerating Object.keys() in node.js that I do not understand. With the following code:
Object.prototype.tuple = function() {
var names = Object.keys(this);
console.log("Dump of names:");
console.log(names);
console.log("FOR loop using indexes:");
for (var k = 0; k < names.length; k++)
{
console.log(names[k]);
}
console.log("FOR loop using enumeration:");
for (var z in names)
{
console.log(z);
}
return this;
};
var x = {a:0, b:0, c:0}.tuple();
I get the following results on the console:
Dump of names:
[ 'a', 'b', 'c' ]
FOR loop using indexes:
a
b
c
FOR loop using enumeration:
0
1
2
tuple
Could somebody explain where does an extra "tuple" come from in the second loop? While defined as function in Object.prototype, it is neither an own property of x object, nor included in names array.
I am using node.js version 0.8.20.
The first loop goes over the properties of x (Object.keys() returns only own properties), while the second one goes over the properties or the array names, including the ones up in the prototype chain.
Thanks to Jonathan Lonowski for clarifications.
I think what #Kuba mentioned above is not correct.
Object.keys, Object.getOwnPropertyNames and other similar method would behave different sightly. Their behaviors are related to a property named enumerable.
I am going to dinner with my friends so I can only give you a helpful link illustrating it. So sorry.
https://developer.mozilla.org/en-US/docs/Enumerability_and_ownership_of_properties
Here's my rather clumsy solution:
// Duplicate last element
{
List<PointF> t;
t = tiles.ToList();
t.Add(tiles.LastOrDefault());
tiles = t.ToArray();
}
The strange fact that .Add does not return the list means one statement is forced to be four.
What's a better e.g. more concise way? Thanks.
I'm finding your example difficult to follow... let me know if this makes sense.
var strings = new[] { "Item 1", "Item 2" };
strings = strings.Concat(new[] { strings.LastOrDefault() }).ToArray();
This example takes an array and duplicates the last item.
In your case it looks like tiles is an array of PointF. If you want to duplicate the last element all you have to do is:
tiles = tiles.Concat(new[] { tiles.LastOrDefault() }).ToArray();
How about this?
it will duplicate your last element what ever it is.
it covers the endcase of an empty array
ArrayList<PointF> t;
t = tiles.toList();
if (t.size() ==0){
//something else or nothing
}else{
t.add(new PointF(t.at(t.size()-1)));
//i am not a C# programmer and i dont even have VS so it could be get() or something
tiles = t.toArray();
}
Preface: I'm working with Processing and I've never used Java.
I have this Processing function, designed to find and return the most common color among the pixels of the current image that I'm working on. the last line complains that "The method color(int) in the type PApplet is not applicable for the arguments (String)." What's up?
color getModeColor() {
HashMap colors = new HashMap();
loadPixels();
for (int i=0; i < pixels.length; i++) {
if (colors.containsKey(hex(pixels[i]))) {
colors.put(hex(pixels[i]), (Integer)colors.get(hex(pixels[i])) + 1);
} else {
colors.put(hex(pixels[i]),1);
}
}
String highColor;
int highColorCount = 0;
Iterator i = colors.entrySet().iterator();
while (i.hasNext()) {
Map.Entry me = (Map.Entry)i.next();
if ((Integer)me.getValue() > highColorCount) {
highColorCount = (Integer)me.getValue();
highColor = (String)me.getKey();
}
}
return color((highColor);
}
The Processing docs that I'm looking at are pretty sparse on the HashMap so I'm not really sure what's going on inside it, but I've been augmenting what's available there with Java docs they point to. But I'm not really grokking what's happening with the types. It looks like the key in the HashMap needs to be a string and the value needs to be an integer, but they come out as objects that I have to cast before using. So I'm not sure whether that's causing this glitch.
Or maybe there's just a problem with color() but the docs say that it'll take a hex value which is what I was trying to use as the key in the HashMap (where I'd rather just use the color itself).
Now that I've talked through this, I'm thinking that the color() function sees the hex value as an int but the hex() function converts a color to a string. And I don't seem to be able to convert that string to an int. I guess I could parse the substrings and reconstruct the color, but there must be some more elegant way to do this that I'm missing. Should I just create a key-value-pair class that'll hold a color and a count and use an arraylist of those?
Thanks in advance for any help or suggestions you can provide!
I'll dig deeper into this, but an initial thought is to employ Java generics so that the compiler will complain about type issues (and you won't get runtime errors):
HashMap<String,Integer> colors = new HashMap<String,Integer>();
So the compiler will know that keys are Strings and elements are Integers. Thus, no casting will be necessary.
I didn't figure it out, but I did work around it. I'm just making my own string from the color components like:
colors.put(red(pixels[i]) + "," + green(pixels[i]) + "," + blue(pixels[i]),1)
and then letting the function drop a color out like this:
String[] colorConstituents = split(highColor, ",");
return color(int(colorConstituents[0]), int(colorConstituents[1]), int(colorConstituents[2]));
This doesn't really seem like the best way to handle it -- if I'm messing with this long-term I guess I'll change it to use an arraylist of objects that hold the color and count, but this works for now.