TestComplete cannot find an object by 2 properties - testcomplete

I have a problem with how TestComplete finds objects by two properties
I find all objects by some property 1 and value 1, then select those having property 2 equal to value 2, get 6 objects
Then I find all objects by property 2 and value 2, then select those having property 1 equal to value 1, again get 6 objects
Then pass to FindAll both properties and get zero objects
var p1 = "NewActionList"
var p2 = "titleBar"
var x1 = Sys["FindAll"](["NativeSlObject.Parent.Name.OleValue"], [p1], 100)
var x2 = Sys["FindAll"](["Parent.NativeSlObject.Parent.Parent.Name.OleValue"], [p2], 100)
x1 = new VBArray(x1).toArray()
x2 = new VBArray(x2).toArray()
for (var i = 0; i < x1.length; i++)
{
if (x1[i].Parent.NativeSlObject.Parent.Parent.Name.OleValue == p2)
{
Log["Message"]("x1")
}
}
for (var i = 0; i < x2.length; i++)
{
if (x2[i].NativeSlObject.Parent.Name.OleValue == p1)
{
Log["Message"]("x2")
}
}
var x = Sys["FindAll"](["NativeSlObject.Parent.Name.OleValue", "Parent.NativeSlObject.Parent.Parent.Name.OleValue"], [p1, p2], 100)
x = new VBArray(x).toArray()
Log["Message"](x.length)
Get x1 six times, x2 six times, and 0

FindAll is searching for one object which will have both parameters you specified:
ativeSlObject.Parent.Name.OleValue = p1
and
Parent.NativeSlObject.Parent.Parent.Name.OleValue = p2
Do you have the object with such properties in the object tree?

I think that such search can be rather slow even if it works. I recommend that you search for the desired objects in several steps using a simpler search criteria.
Also, you can find it easier to use the Name Mapping functionality along with its Required Children and Extended Find features.

Related

How I connect dots using A* (Astart) pathfinding system? in GODOT

I'm trying to do something a little bit different then the usual.
I have a 3D gridmap node setup and I'm trying to autogenerate the dots and connections using A*
Instead of creating obstacles tiles, I'm creating walls in between the tiles, so the tiles are still walkable, you just cannot pass through a wall . I figure it that out all already
but I have no idea how to code how to connect the points in a easy way and not connect points that has walls in between...
I'm using a RaycastCast Node to detect the wall, and his position as it walk through every gridtile
but I can't figure it out a nested loop to find the neighbors points to connect
this is what I tried to do (obviously get_closest_point() is not working the way I wanted).
If I could get a point using only Vector3 Coordinates, I think I could make it work.
EXTRA: if you guys can show me a way to clean the code, especially on the "FORs" syntaxes, because I kind don't know what I'm doing
Any other clean code recommendations would be amazing and very much welcomed
At the end has a visual draw(image) of the logic of the idea.
onready var rc = $RayCast
onready var aS = AStar.new()
var floor_size = Vector3(12,0,12)
var origin = Vector3(-5.5, 0.5, -2.5)
var FRONT = Vector3(1,0,0)
var RIGHT = Vector3(0,0,1)
var BACK = Vector3(-1,0,0)
var LEFT = Vector3(-1,0,0)
func set_walkable():
var value = 0
var value2 = 0
var i = 0
for _length in range (origin.x, origin.x + floor_size.x + 1):
value += 1
value2 = 0
for _width in range(origin.z, origin.z + floor_size.z):
i += 1
value2 += 1
aS.add_point(i, Vector3(origin.x + value -1 , 0.5, origin.z + value2 -1) , 1.0)
value = 0
for _u in range(origin.x, origin.x + floor_size.x + 1):
value += 1
value2 = 0
for _v in range(origin.z, origin.z + floor_size.z):
value2 += 1
var from = aS.get_closest_point(Vector3(origin.x + value ,0.5, origin.z + value2) ) # Current
rc.translation = Vector3(origin.x + value -1 ,0.5, origin.z + value2 -1)
draw_points()
print(rc.translation)
rc.cast_to = FRONT
var to = aS.get_closest_point(rc.translation) # Front
if from != -1 and !rc.is_colliding():
aS.connect_points(from, to)
draw_connections(Vector3(rc.translation.x + 0.5,rc.translation.y,rc.translation.z))
rc.cast_to = BACK
to = aS.get_closest_point(rc.translation) # back
if from != -1 and !rc.is_colliding():
aS.connect_points(from, to)
draw_connections(Vector3(rc.translation.x + -0.5,rc.translation.y,rc.translation.z))
rc.cast_to = RIGHT
to = aS.get_closest_point(rc.translation) # right
if from != -1 and !rc.is_colliding():
aS.connect_points(from, to)
draw_connections(Vector3(rc.translation.x,rc.translation.y,rc.translation.z + 0.5))
rc.cast_to = LEFT
to = aS.get_closest_point(rc.translation) # left
if from != -1 and !rc.is_colliding():
aS.connect_points(from, to)
draw_connections(Vector3(rc.translation.x + 0.5,rc.translation.y,rc.translation.z + -0.5))
func draw_points(): # Make points visible
var cube = MeshInstance.new()
cube.mesh = CubeMesh.new()
cube.translation = rc.translation
cube.scale = Vector3(0.25,0.25,0.25)
add_child(cube)
print("Cubo adicionado")
func draw_connections(position): # Make connections visible
var line = MeshInstance.new()
line.mesh = PlaneMesh.new()
line.scale = Vector3(0.03,0.03,0.03)
line.translation = position
add_child(line)
print("Cubo adicionado")
Convert between Coordinates and Point ids
Let us establish a mapping between coordinates and point ids. Given that we have a floor_size, this is easy:
func vector_to_id(vector:Vector3, size:Vector3) -> int:
return int(int3(vector).dot(dimension_size(size)))
func id_to_vector(id:int, size:Vector3) -> Vector3:
var s:Vector3 = dimension_size(size)
var z:int = int(id / s.z)
var y:int = int((id % int(s.z)) / s.y)
var x:int = id % int(s.y)
return Vector3(x, y, z)
func int3(vector:Vector3) -> Vector3:
return Vector3(int(vector.x), int(vector.y), int(vector.z))
func dimension_size(size:Vector3) -> Vector3:
return Vector3(1, int(size.x + 1), int(size.x + 1) * int(size.y + 1))
Possible optimizations:
Store dimension_size(floor_size) and use that directly.
Skip calling int3 on the condition that the values you pass to vector_to_id are guaranteed to be integer.
We will need a function to get the total number of points:
func total_size(size:Vector3) -> int:
return int(size.x + 1) * int(size.y + 1) * int(size.z + 1)
Explanation
Let us start at 1D (one dimension). We will only have one coordinate. So we have an hypothetical Vector1 that has an x property. We are simply putting things in a line.
Then the mapping is trivial: to convert from the coordinates to the id, we take id = int(vector.x), and if we want the coordinate we simply do vector = Vector1(id).
Now, let us move to 2D. We have Vector2 with x and y. Thankfully we have a size (there are ways to do the mapping when the size is not known, but having a size is convenient).
Thus, we will be doing a 2D grid, with some width and height. The y coordinate tells us the row in which we are, and x tells us the position in the row.
Then if we have some id, we need to figure out how many rows we need to get there, and then in what position in that row we are. Figuring out the row is easy, we divide by the width of the grid. And the position in the row is the reminder. One caveat: We are measuring from 0 (so a width of 0 actually means 1 element per row).
We have:
func id_to_vector(id:int, size:Vector2) -> Vector2:
var y:int = int(id / (size.x + 1))
var x:int = id % int(size.x + 1)
return Vector2(x, y)
How about going the other way around? Well, we multiply y for the length of a row (the width), and add x:
func vector_to_id(vector:Vector2, size:Vector2) -> int:
return int(vector.x) + int(vector.y) * int(size.x + 1)
Notice:
We didn't need size.y.
We need size.x + 1 in both functions.
vector_to_id looks very similar to a dot product.
Thus, let us make a new function that returns the vector with which we would be making the dot product:
func dimension_size(size:Vector2) -> Vector2:
return Vector2(1, int(size.x + 1))
And use it:
func vector_to_id(vector:Vector2, size:Vector2) -> int:
return int(vector.dot(dimensional_size(size)))
func id_to_vector(id:int, size:Vector2) -> Vector2:
var s = dimensional_size(size)
var y:int = int(id / int(s.y))
var x:int = id % int(s.y)
return Vector2(x, y)
Note If there is no guarantee that vector only has integers in vector_to_id, the fractional part in the dot product make lead to a wrong result. Which is why I have a function to make it have only integer.
Time for 3D. We have Vector3 with x, y and z. We are making a 3D grid. Now the z will tell us the layer, and each layer is a 2D grid.
Let us review dimensional_size, We had:
func dimension_size(size:Vector2) -> Vector2:
return Vector2(1, int(size.x + 1))
That is the size of an element (1), the size of a row(size.x + 1), we need to add the size of a layer. That is, the size of the 2D grid, which is just width times height.
func dimension_size(size:Vector3) -> Vector3:
return Vector3(1, int(size.x + 1), int(size.x + 1) * int(size.y + 1))
And how do we get z from the id? We divide by the size of a grid (so we know on what grid we are). Then from the reminder of that division we can find y:
func vector_to_id(vector:Vector3, size:Vector3) -> int:
return int(vector.dot(dimensional_size(size)))
func id_to_vector(id:int, size:Vector3) -> Vector3:
var s = dimensional_size(size)
var z:int = int(id / int(s.z))
var y:int = int(int(id % int(s.z)) / int(s.y))
var x:int = id % int(s.y)
return Vector2(x, y, z)
In fact, technically, all these coordinates are computed on the same form:
func id_to_vector(id:int, size:Vector3) -> Vector3:
var s = dimensional_size(size)
var tot = total_size(size)
var z:int = int(int(id % int(tot)) / int(s.z))
var y:int = int(int(id % int(s.z)) / int(s.y))
var x:int = int(int(id % int(s.y)) / int(s.x))
return Vector2(x, y, z)
Except, there is no need to take the reminder with the total size because id should always be less than that. And there is no need to divide by s.x because the size of a single element is always 1. And I also removed some redundant int casts.
What is total_size? The next element of dimensional_size, of course:
func dimension_size(size:Vector3) -> Vector3:
return Vector3(1, int(size.x + 1), int(size.x + 1) * int(size.y + 1))
func total_size(size:Vector3) -> int:
return int(size.x + 1) * int(size.y + 1) * int(size.z + 1)
Checking connectivity
And a way to check connectivity:
func check_connected(start:Vector3, end:Vector3) -> bool:
rc.transform.origin = start
rc.cast_to = end
rc.force_update_transform()
rc.force_raycast_update()
return !raycast.is_colliding()
And you had the right idea with FRONT, RIGHT, BACK and LEFT but put them in an array:
var offsets = [Vector3(1,0,0), Vector3(0,0,1), Vector3(-1,0,0), Vector3(-1,0,0)]
Note I'm calling force_update_transform and force_raycast_update because are doing multiple raycast checks on the same frame.
Populating AStar
Alright, enough setup, we can now iterate:
for id in total_size(floor_size):
pass
On each iteration, we need to get the vector:
for id in total_size(floor_size):
var vector = id_to_vector(id, floor_size)
Posible optimization: Iterate over the vector coordinates directly to avoid calling id_to_vector.
We can add the vector to AStar:
for id in total_size(floor_size):
var vector = id_to_vector(id, floor_size)
aS.add_point(id, vector)
Next we need the adjacent vectors:
for id in total_size(floor_size):
var vector = id_to_vector(id, floor_size)
aS.add_point(id, vector)
for offset in offsets:
var adjacent = vector + offset
Let us add them to AStar too:
for id in total_size(floor_size):
var vector = id_to_vector(id, floor_size)
aS.add_point(id, vector)
for offset in offsets:
var adjacent = vector + offset
var adjacent_id = vector_to_id(adjacent, floor_size)
aS.add_point(adjacent_id, adjacent)
Possible optimizations:
Do not add if has_point returns true.
If the id of the adjacent vector is lower, do not process it.
Modify offsets so that you only check adjacent position that are yet to be added (and thus preventing the prior two cases).
Let us check connectivity:
for id in total_size(floor_size):
var vector = id_to_vector(id, floor_size)
aS.add_point(id, vector)
for offset in offsets:
var adjacent = vector + offset
var adjacent_id = vector_to_id(adjacent, floor_size)
aS.add_point(adjacent_id, adjacent)
if check_connected(vector, adjacent):
pass
And tell the AStar about the connectivity:
for id in total_size(floor_size):
var vector = id_to_vector(id, floor_size)
aS.add_point(id, vector)
for offset in offsets:
var adjacent = vector + offset
var adjacent_id = vector_to_id(adjacent, floor_size)
aS.add_point(adjacent_id, adjacent)
if check_connected(vector, adjacent):
connect_points(id, adjacent_id)

Android Kotlin replace while with for next loop

We have a HashMap Integer/String and in Java we would iterate over the HashMap and display 3 key value pairs at a time with the click of a button. Java Code Below
hm.put(1, "1");
hm.put(2, "Dwight");
hm.put(3, "Lakeside");
hm.put(4, "2");
hm.put(5, "Billy");
hm.put(6, "Georgia");
hm.put(7, "3");
hm.put(8, "Sam");
hm.put(9, "Canton");
hm.put(10, "4");
hm.put(11, "Linda");
hm.put(12, "North Canton");
hm.put(13, "5");
hm.put(14, "Lisa");
hm.put(15, "Phoenix");
onNEXT(null);
public void onNEXT(View view){
etCity.setText("");
etName.setText("");
etID.setText("");
X = X + 3;
for(int L = 1; L <= X; L++ ){
String id = hm.get(L);
String name = hm.get(L = L + 1);
String city = hm.get(L = L + 1);
etID.setText(id);
etName.setText(name);
etCity.setText(city);
}
if(X == hm.size()){
X = 0;
}
}
We decoded to let Android Studio convert the above Java Code to Kotlin
The converter decide to change the for(int L = 1; L <= X; L++) loop to a while loop which seemed OK at first then we realized the while loop was running for 3 loops with each button click. Also Kotlin complained a lot about these line of code String name = hm.get(L = L + 1); String city = hm.get(L = L + 1);
We will post the Kotlin Code below and ask the question
fun onNEXT(view: View?) {
etCity.setText("")
etName.setText("")
etID.setText("")
X = X + 3
var L = 0
while (L <= X) {
val id = hm[L - 2]
val name = hm.get(L - 1)
val city = hm.get(L)
etID.setText(id)
etName.setText(name)
etCity.setText(city)
L++
}
if (X == hm.size) {
X = 0
}
}
We tried to write a For Next Loop like this for (L in 15 downTo 0 step 1)
it seems you can not count upTo so we thought we would use the hm:size for the value 15 and just use downTo
So the questions are
How do we use the Kotlin For Next Loop syntax and include the hm:size in the construct?
We have L declared as a integer but Kotlin will not let us use
L = L + 1 in the While loop nor the For Next Loop WHY ?
HERE is the strange part notice we can increment X by using X = X + 3
YES X was declared above as internal var X = 0 as was L the same way
Okay, I'll bite.
The following code will print your triples:
val hm = HashMap<Int, String>()
hm[1] = "1"
hm[2] = "Dwight"
hm[3] = "Lakeside"
hm[4] = "2"
hm[5] = "Billy"
hm[6] = "Georgia"
hm[7] = "3"
hm[8] = "Sam"
hm[9] = "Canton"
hm[10] = "4"
hm[11] = "Linda"
hm[12] = "North Canton"
hm[13] = "5"
hm[14] = "Lisa"
hm[15] = "Phoenix"
for (i in 1..hm.size step 3) {
println(Triple(hm[i], hm[i + 1], hm[i + 2]))
}
Now let's convert the same idea into a function:
var count = 0
fun nextTriplet(hm: HashMap<Int, String>): Triple<String?, String?, String?> {
val result = mutableListOf<String?>()
for (i in 1..3) {
result += hm[(count++ % hm.size) + 1]
}
return Triple(result[0], result[1], result[2])
}
We used a far from elegant set of code to accomplish an answer to the question.
We used a CharArray since Grendel seemed OK with that concept of and Array
internal var YY = 0
val CharArray = arrayOf(1, "Dwight", "Lakeside",2,"Billy","Georgia",3,"Sam","Canton")
In the onCreate method we loaded the first set of data with a call to onCO(null)
Here is the working code to iterate over the CharArray that was used
fun onCO(view: View?){
etCity.setText("")
etName.setText("")
etID.setText("")
if(CharArray.size > YY){
val id = CharArray[YY]
val name = CharArray[YY + 1]
val city = CharArray[YY + 2]
etID.setText(id.toString())
etName.setText(name.toString())
etCity.setText(city.toString())
YY = YY + 3
}else{
YY = 0
val id = CharArray[YY]
val name = CharArray[YY + 1]
val city = CharArray[YY + 2]
etID.setText(id.toString())
etName.setText(name.toString())
etCity.setText(city.toString())
YY = YY + 3
}
Simple but not elegant. Seems the code is a better example of a counter than iteration.
Controlling the For Next Look may involve less lines of code. Control of the look seemed like the wrong direction. We might try to use the KEY WORD "when" to apply logic to this question busy at the moment
After some further research here is a partial answer to our question
This code only show how to traverse a hash map indexing this traverse every 3 records needs to be added to make the code complete. This answer is for anyone who stumbles upon the question. The code and a link to the resource is provide below
fun main(args: Array<String>) {
val map = hashMapOf<String, Int>()
map.put("one", 1)
map.put("two", 2)
for ((key, value) in map) {
println("key = $key, value = $value")
}
}
The link will let you try Kotlin code examples in your browser
LINK
We only did moderate research before asking this question. Our Appoligies. If anyone is starting anew with Kotlin this second link may be of greater value. We seldom find understandable answers in the Android Developers pages. The Kotlin and Android pages are beginner friendlier and not as technical in scope. Enjoy the link
Kotlin and Android

Sort multiple lists lua

How can I sort 2 lists y location ( map tiles and people ) and draw them in order dependent of y. 2 lists I want to use:
map = {}
map.y = {60,10,40,80}
map.t = {0,0,1,1} -- type
people = {}
people.y = {0,100}
people.t = {0,1} -- type
I can currently sort and draw a single list of hero and boxes.
Sort / draw code:
box1 = love.graphics.newImage("box1.png")
box2 = love.graphics.newImage("box2.png")
box3 = love.graphics.newImage("box3.png")
hero = love.graphics.newImage("hero.png")
object = {
x = {0, 50,100,200},
y = {0,200, 50,100},
g = {0,1,2,3}
}
function sortIndex(item)
local i
local id = {} -- id list
for i = 1, #item.x do -- Fill id list (1 to length)
id[i] = i
end
-- print( unpack(id) ) -- Check before
table.sort(id,sortY)-- Sort list
-- print( unpack(id) ) -- Check after
item.sort = id -- List added to object.sort
-- Sort id, using item values
function sortY(a,b)
return item.y[a] < item.y[b]
end
end
function drawObject()
local i,v, g,x,y
for i = 1, #object.x do
v = object.sort[i] -- Draw in order
x = object.x[v]
y = object.y[v]
g = object.g[v]
if g == 0 then g = hero -- set to an image value
elseif g == 1 then g = box1
elseif g == 2 then g = box2
elseif g == 3 then g = box3
end
love.graphics.draw(g,x,y,0,7,7)
end
end
Update sort:
sortIndex(object)
My function sorts an id list comparing a y location list. The id is used to draw objects in order dependent of their y. How can I sort 2 id lists together comparing 2 y location lists, then draw them in order?
Maybe when drawing, switch from map tiles to people dependent on y, but I don't know how.
Might be related to your previous question a lot: Returning A Sorted List's Index in Lua
I assume if your height can be 1,2 and 3 (with 1 being on the top), you first want to render all tiles at Y1, then all people at Y1, then Y2 and Y3. To do that, you'll have to make a combined list and sort that:
map = {}
map.y = {60,10,40,80}
map.t = {0,0,1,1} -- type
people = {}
people.y = {0,100}
people.t = {0,1} -- type
local all = {}
local map_y = map.y
local offset = #map_y
local people_y = people.y
-- Fill the list with map tiles
for i=1,offset do
all[i] = {1,i,map_y[i]} --{type,index,y}
end
-- Fill the list with people
for i=1,#people_y do
all[i+offset] = {2,i,people_y[i]}
end
-- Do the sorting
-- It works a bit like your previous question:
-- 'all' contains "references":
-- They tell us is it's from map/people + the index
-- We sort the references using the third element in it:
-- The 'y' variable we put there during the first 2 loops
table.sort(all,function(a,b)
return a[3] < b[3]
end)
-- Printing example
-- The references are sorted using the 'y' field of your objects
-- With v[1] we know if it's from map/people
-- The v[2] tells us the index in that ^ table
-- The v[3] is the 'y'-field. No real need to remove it
for k,v in pairs(all) do
print(v[1] == 1 and "Map" or "Person",v[2],"with y being",v[3])
end
Output:
Person 1 with y being 0
Map 2 with y being 10
Map 3 with y being 40
Map 1 with y being 60
Map 4 with y being 80
Person 2 with y being 100
There are 2 things I want to add, that doesn't have anything to do with the question of my answer:
Maybe it would be easier if you have a table for each element.
Your people would be {0,0} and {100,1} which might be easier to manipulate.
If you prefer your stuff always sorted, you might want to use this: Sorted List. If you keep a sorted list of all your objects, you don't have to sort the list everytime you add/remove an element, or worse, each time you render. (depending if people move) This might help with performance if you're planning to have a lot of map/people objects. (Sorted List could be useful for your current data system, but also the {y=1,t=1} one)
function sortIndex(...)
sorted = {} -- global
local arrays_order = {}
for arr_index, array in ipairs{...} do
arrays_order[array] = arr_index
for index = 1, #array.y do
table.insert(sorted, {array = array, index = index})
end
end
table.sort(sorted,
function (a,b)
local arr1, arr2 = a.array, b.array
local ind1, ind2 = a.index, b.index
return arr1.y[ind1] < arr2.y[ind2] or
arr1.y[ind1] == arr2.y[ind2] and arrays_order[arr1] < arrays_order[arr2]
end)
end
function drawAll()
for _, elem_info in ipairs(sorted) do
local array = elem_info.array
local index = elem_info.index
local x = array.x[index]
local y = array.y[index]
if array == map then
-- draw a map tile with love.graphics.draw()
elseif array == people then
-- draw a human with love.graphics.draw()
end
end
end
sortIndex(map, people) -- to draw map tiles before people for the same y

Collect partial results from parallel streams

In Java8, processing pairs of items in two parallel streams as below:
final List<Item> items = getItemList();
final int l = items.size();
List<String> results = Collections.synchronizedList(new ArrayList<String>());
IntStream.range(0, l - 1).parallel().forEach(
i -> {
Item item1 = items.get(i);
int x1 = item1.x;
IntStream.range(i + 1, l).parallel()
.forEach(j -> {
Item item2 = items.get(j);
int x2 = item2.x;
if (x1 + x2 < 200) return;
// code that writes to ConcurrentHashMap defined near results
if (x1 + x2 > 500) results.add(i + " " + j);
});
}
);
Each stream pair writes to ConcurrentHashMap, and depending on certain conditions it may terminate the stream execution by calling return; or it may write to a synchronized list.
I want to make streams return the results like return i + " " + j and collect those results into a list strings outside. It should be partial as returning nothing must be supported (in case when x1 + x2 < 200).
What would be the most time-efficient (fastest code) way to achieve that?
In this answer, I will not address the time efficiency, because there are correctness problems that should be handled beforehand.
As I said in the comments, it is not possible to stop the stream execution after a certain condition if we parallelize the stream. Otherwise, there might be some pairs (i,j) that are already being executed that are numerically after a pair that triggered the stop condition x1 + x2 < 200.
Another issue is the return; inside the lambda, all it will do is skip the second if for the j for which x1 + x2 < 200 holds, but the stream will continue with j+1.
There is no straightforward way to stop a stream in Java, but we can achieve that with allMatch, as we can expect that as soon as it finds a false value, it will short-circuit and return false right way.
So, this would be a correct version of your code:
IntStream.range(0, l - 1).allMatch(i -> {
int x1 = items.get(i).x;
return IntStream.range(i + 1, l).allMatch(j -> {
int x2 = items.get(j).x;
if (x1 + x2 < 200) {
return false;
} else {
if (x1 + x2 > 500) results2.add(i + " " + j);
return true;
}
});
});
For the following example, with the constructor Item(int x, int y):
final List<Item> items = Arrays.asList(
new Item(200, 0),
new Item(100, 0),
new Item(500, 0),
new Item(400, 0),
new Item(1, 0));
The contents of results in my version is:
[0 2, 0 3, 1 2]
With your code (order and elements vary in each execution):
[2 4, 2 3, 1 2, 0 3, 0 2]
I think this will be more efficient (haven't done any micro benchmarking though):
IntStream.range(0,l-1).forEach(
i -> IntStream.range(i+1,l)
.filter(j -> items.get(i).x + items.get(j).x > 500)
.forEach(j -> results.add(i + " " + j)));
However, if I was really worried about the time taken to do this, I'd pay more attention to what kind of a List implementation is used for items. Perhaps even convert the list to a HashMap<Integer, Item> before getting into the lambda. For example, if items is a LinkedList, any improvement to the lambda may be inconsequential because items.get() will eat up all the time.

Combinations with multiple containers of varying sizes

If you know what this kind of problem is called, let me know (unless you actually know the answer to the question).
If I have a set Z of objects, is there an algorithm for diving them up between a bunch of containers (each holding a certain number of objects)?
To slightly complicate the problem, let's assume the set of objects we start with has a subset X. There are X containers, and each container must hold a single element of X, in addition to other objects (if it has room).
The best way I can think of doing this currently is looking at the disjunction of Z and X, let's call it Y. Then we can generate the z choose x combinations, and then expand that out for all possible combinations of x.
Example:
The actual problem is basically generating all events in a space. Suppose we have two event triggers (X) and 2 event arguments (Y), where Z = X U Y. Each event must have a trigger, and it can have 0...N arguments (depending on the type of event, but that isn't important for now. A trigger can also be an argument. Clearly, in this situation we can have a single event with one trigger and 3 arguments (one of which is the second trigger)
Our event space is as follows (Trigger[Arguments], + indicates a new event):
X1[] + X2[]
X1[Y1] + X2[]
X1[Y2] + X2[]
X1[] + X2[Y1]
X1[] + X2[Y2]
X1[Y1] + X2[Y2]
X1[Y2] + X2[Y1]
X1[X2]
X1[X2,Y1]
X1[X2,Y2]
X1[X2,Y1,Y2]
X2[X1]
X2[X1,Y1]
X2[X1,Y2]
X2[X1,Y1,Y2]
I'm pretty sure that's all the combinations.
Update:
After thinking a bit more about the problem, I have a few thoughts on constraints and stuff: Rules for creating "events":
1) There is an event for every trigger, and every event must have a trigger
2) Event must have > 0 arguments
3) Events cannot share arguments
4) Triggers can be used as arguments
For a brute force solution, perhaps one could generate all permutations of the triggers + events and then eliminate results that don't match the above 4 rules, and treat the ordering as grouping of events?
Thanks for any problem names or ideas!
Algorithm:
For all nonempty subsets Triggers of X:
For all maps from (X \ Triggers) to X:
For all maps from Y to (X union {None}):
print the combination, where an assignment of y in Y to None means y is omitted
In Python:
def assignments(xs, ys):
asgns = [[]]
for x in xs:
asgns1 = []
for y in ys:
for asgn in asgns:
asgn1 = asgn[:]
asgn1.append((x, y))
asgns1.append(asgn1)
asgns = asgns1
return asgns
def combinations(xs, ys):
xroleasgns = assignments(xs, ('argument', 'trigger'))
for xroleasgn in xroleasgns:
triggers = [x for (x, role) in xroleasgn if role == 'trigger']
if (xs or ys) and not triggers:
continue
xargs = [x for (x, role) in xroleasgn if role == 'argument']
for xargasgn in assignments(xargs, triggers):
for yargasgn in assignments(ys, [None] + triggers):
d = dict((x, []) for x in triggers)
for xarg, t in xargasgn:
d[t].append(xarg)
for yarg, t in yargasgn:
if t is not None:
d[t].append(yarg)
print ' + '.join('%s[%s]' % (t, ','.join(args)) for (t, args) in d.iteritems())
"""
>>> assign.combinations(['X1','X2'],['Y1','Y2'])
X1[X2]
X1[X2,Y1]
X1[X2,Y2]
X1[X2,Y1,Y2]
X2[X1]
X2[X1,Y1]
X2[X1,Y2]
X2[X1,Y1,Y2]
X2[] + X1[]
X2[] + X1[Y1]
X2[Y1] + X1[]
X2[] + X1[Y2]
X2[] + X1[Y1,Y2]
X2[Y1] + X1[Y2]
X2[Y2] + X1[]
X2[Y2] + X1[Y1]
X2[Y1,Y2] + X1[]
"""
Here is my java implementation over9000's solution to the original problem:
public static void main(String[] args) throws Exception {
ArrayList xs = new ArrayList();
ArrayList ys = new ArrayList();
xs.add("X1");
xs.add("X2");
ys.add("Y1");
ys.add("Y2");
combinations(xs,ys);
}
private static void combinations(ArrayList xs, ArrayList ys) {
ArrayList def = new ArrayList();
def.add("argument");
def.add("trigger");
ArrayList<ArrayList> xroleasgns = assignments(xs, def);
for(ArrayList xroleasgn:xroleasgns){
// create triggers list
ArrayList triggers = new ArrayList();
for(Object o:xroleasgn){
Pair p = (Pair)o;
if("trigger".equals(p.b.toString()))
triggers.add(p.a);
}
if((xs.size()>0 || ys.size()>0) && triggers.size()==0)
continue;
// create xargs list
ArrayList xargs = new ArrayList();
for(Object o:xroleasgn){
Pair p = (Pair)o;
if("argument".equals(p.b.toString()))
xargs.add(p.a);
}
// Get combinations!
for(ArrayList xargasgn:assignments(xargs,triggers)){
ArrayList yTriggers = new ArrayList(triggers);
yTriggers.add(null);
for(ArrayList yargasgn:assignments(ys,yTriggers)){
// d = dict((x, []) for x in triggers)
HashMap<Object,ArrayList> d = new HashMap<Object,ArrayList>();
for(Object x:triggers)
d.put(x, new ArrayList());
for(Object o:xargasgn){
Pair p = (Pair)o;
d.get(p.b).add(p.a);
}
for(Object o:yargasgn){
Pair p = (Pair)o;
if(p.b!=null){
d.get(p.b).add(p.a);
}
}
for(Entry<Object, ArrayList> e:d.entrySet()){
Object t = e.getKey();
ArrayList args = e.getValue();
System.out.print(t+"["+args.toString()+"]"+"+");
}
System.out.println();
}
}
}
}
private static ArrayList<ArrayList> assignments(ArrayList xs, ArrayList def) {
ArrayList<ArrayList> asgns = new ArrayList<ArrayList>();
asgns.add(new ArrayList()); //put an initial empty arraylist
for(Object x:xs){
ArrayList asgns1 = new ArrayList();
for(Object y:def){
for(ArrayList<Object> asgn:asgns){
ArrayList asgn1 = new ArrayList();
asgn1.addAll(asgn);
asgn1.add(new Pair(x,y));
asgns1.add(asgn1);
}
}
asgns = asgns1;
}
return asgns;
}

Resources