I have a list of lines Lines=([('B', 'C'), ('D', 'A'), ('D', 'C'), ('A', 'B'), ('D', 'B')]) and geometry = ('B', 'C', 'D') is a list of points that set up the triangle (B,C,D).
I want to check whether geometry can be set up from list of lines in Lines. How can I create a function to check that status? True or False.
Sample Functionality with input Lines:
>> Lines=([('B', 'C'), ('D', 'A'), ('D', 'C'), ('A', 'B'), ('D', 'B'),])
>> geometry1 = ('B', 'C', 'D')
>> check_geometry(Lines, geometry1)
True
>> geometry2 = ('A', 'B', 'E')
>> check_geometry(Lines, geometry2)
False
This is my code, but the result is wrong:
import itertools
def check_geometry(line, geometry):
dataE = [set(x) for x in itertools.combinations(geometry, 2)]
for data in dataE:
if data not in line:
return False
return True
Lines = [('B', 'C'), ('D', 'A'), ('D', 'C'), ('A', 'B'), ('D', 'B'),]
geometry1 = ('B', 'C', 'D')
print check_geometry(Lines, geometry1)
Output:
False
You could use the built-in all to do this, making sure to first sort the list contents since their order might differ than that generated from itertools.combinations:
sLines = [tuple(sorted(l)) for l in Lines]
dataE = itertools.combinations('BCD', 2)
Now you can call all which will check that every value in dataE is present in sLines:
all(l1 in sLines for l1 in dataE)
Which will return True.
So, your check_geometry function could look something like:
def check_geometry(line, geometry):
sLines = [tuple(sorted(l)) for l in line]
dataE = itertools.combinations(geometry, 2)
return all(l1 in sLines for l1 in dataE)
Calls made will now check if the Lines contain the geometry:
check_geometry(Lines, 'BCD')
# returns True
check_geometry(Lines, 'ABE')
# returns False
To generalize this a bit, we can drop itertools.combinations and instead utilize zip. The following makes some appropriate changes to the function in order to acommodate zip but performs similar stuff:
def check_geometry(line, geometry):
sLines = [sorted(l) for l in line]
dataE = [sorted(x) for x in zip(geometry, geometry[1:] + geometry[:1])]
return all(l1 in sLines for l1 in dataE)
The key difference here is:
dataE is now a list of lists containing the result of zip(geometry, geometry[1:] + geometry[:1]). What zip does in this case is it takes a string like "BCDA" and the same string with the first element added to the end geometry[1:] + geometry[:1] (i.e "CDAB") and creates entries signifying the sides of a shape:
>>> s = "BCDA"
>>> s[1:] + s[:1]
>>> 'CDAB'
>>> list(zip(s, s[1:] + s[:1]))
[('B', 'C'), ('C', 'D'), ('D', 'A'), ('A', 'B')]
Now we can check that a geometry with points "BCDA" can be constructed by the lines in Lines:
check_geometry(Lines, "BCD")
# True
check_geometry(Lines, "BCDA")
# True
check_geometry(Lines, "BCDF")
# False
Note 1: Lines can be written as:
Lines=[('B', 'C'), ('D', 'A'), ('D', 'C'), ('A', 'B'), ('D', 'B')]
The parenthesis () and comma , have no additional effect here, you can drop them :-) .
Note 2: The geometry parameter for check_geometry can be any iterable (tuples, lists, strings):
check_geometry(lines, "BCD") == check_geometry(lines, ('B', 'C', 'D'))
Creating and passing a tuple to it seems somewhat odd in this case (alas, you might have a good reason to do so). Unless reasons require it, I would suggest going with strings as the value for parameter geometry.
I think A,B,C can be string or whatever which define a point that set up a line
Okay, I'll be using strings for my answer then, you should be able to adjust the code to your needs.
def check_for_triangle(tri, lines):
lines_needed = zip(tri, (tri[1], tri[2], tri[0]))
return all(line in lines or line[::-1] in lines for line in lines_needed)
lines=[('B', 'C'), ('D', 'A'), ('D', 'C'), ('A', 'B'), ('D', 'B')]
tri1 = ('B', 'C', 'D')
tri2 = ('A', 'B', 'E')
print(check_for_triangle(tri1, lines)) # True
print(check_for_triangle(tri2, lines)) # False
The idea is to generate all lines (represented by a pair of points) we need to find in lines for a given triangle with zip. After that, we check whether all these lines can be found in lines.
Checking for line[::-1] as well is needed because the line ('A', 'B') is the same line as ('B', 'A').
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With