Looking through a list of lists for specific values - python-3.x

I need reada .txt file and find a specific pattern of T's, namely T's arranged in a cross-pattern.
Here's what I've done so far, and its output when I print is below:
def find_treasure(mapfile):
lst = []
with open(mapfile, 'r') as rf:
for line in rf:
lst.append(line.split())
print(lst)
Output
My initial idea was to do something like using 2 for loops to go through each item in the list and then look at each letter/ character in the item itself, but I kept getting list index range errors or its not working at all.
for i in range(len(lst)):
for j in range(len(lst[i])):
if lst[i][j] == 'T':
print('WHy')
else:
print('why am i here why')
Do you guys have any advice?
EDIT: Sample input:
WWWWWWWWWWWWWWWWWWWWWWW.TTT..^^^^...WWWWWWWW
WWWWWWWWWWWWWWWWWWWWWW...T..^^^^....WWWWWWWW
WWWWWWWWWWWWWWWWWWWWWW......^^^......WWWWWWW
WWWWWWWWWWWWWWWWWWWWW..T.....^^^^..T.WWWWWWW
WWWWWWWWWWWWWWWWWWWWW........^^^^..T.WWWWWWW
WWWWWWWWWWWWWWWWWWWW........^^^....T.WWWWWWW
WWWWWWWWWWWWWWWWWWWW........^^^......WWWWWWW
WWWWWWWWWWWWWWWWWWWWWW.....^^^^.....WWWWWWWW
WWWWWWWWWWWWWWWWWWWWWW.....^^^......WWWWWWWW
WWWWWWWWWWWWWWWWWWWWWWW....^^......WWWWWWWWW
WWWWWWWWWWWWWWWWWWWWWW......^.....WWWWWWWWWW
WWWWWWWWWWWWWWWWWWWWW............WWWWWWWWWWW
WWWWWWWWWWWWWWWWWWWW....T......WWWWWWWWWWWWW
WWWWW...WWWWWWWWWWWWW..T.T.....WWWWWWWWWWWWW
WWWW..TTT.WWWWWWWWWWW...T.....WWWWWWWWWWWWWW
WWWWW.......WWWWWWWWWWW......WWWWWWWWWWWWWWW
WWWWWWWW...T.WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW
WWWWWWWWW....WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW
WWWWWWWWWW.T.WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW
WWWWWWWWWWW.WWWWWWWWWW.....WWWWWWWWWWWWWWWWW
WWWWWWWWWWWWWWWWWWWWW....T..WWWWWWWWWWWWWWWW
WWWWWWWWWWWWWWWWWWWWWWW.TTT..WWWWWWWWWWWWWWW
WWWWWWWWWWWWWWWWWWWWWWW..T..WWWWWWWWWWWWWWWW
WWWWWWWWWWWWWWWWWWWWWW...WWWWWWWWWWWWWWWWWWW
WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW
WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW
WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW
W: WATER
T: TREE
.: GRASS
^: MOUNTAIN
And the expected output is: (21,25)

This is not a total response, but I see two problems in your code.
First, as Tadhg mention it, your find_treasure does not return any value, that could be causing the range errors.
Once you connect that, your other block remains. And the reason that you are reaching your why am i here why statement it's cause the split() method without a separator parameter just split the blank spaces. If you want to separate each value from the line, you should use lst.append(list(line)) this would create a matrix with all the elements of your input to be accessed with mat[][]
I hope this helps you =).

I'm assuming by "T's arranged in a cross pattern", you mean this:
*T*
TTT
*T*
Where * is anything but a T.
So to identify a cross pattern centered at the location lst[i][j], all the indices surrounding it must be equal to T.
def isCrossAt(lst, i, j):
return lst[i - 1][j] == 'T' and \
lst[i + 1][j] == 'T' and \
lst[i][j - 1] == 'T' and \
lst[i][j + 1] == 'T' and \
lst[i][j] == 'T'
This means that you only need to check for crosses centered at the second through the second-last row, and the second through the second-last column.
def findCrosses(lst):
for i in range(1, len(lst) - 1):
row = lst[i]
for j in range(1, len(row) - 1):
# Copy the isCrossAt logic here to save a function call
foundCross = lst[i - 1][j] == 'T' and \
lst[i + 1][j] == 'T' and \
lst[i][j - 1] == 'T' and \
lst[i][j + 1] == 'T' and \
lst[i][j] == 'T'
if foundCross:
return (i, j)
Let's test this using your string.
lst = """WWWWWWWWWWWWWWWWWWWWWWW.TTT..^^^^...WWWWWWWW
WWWWWWWWWWWWWWWWWWWWWW...T..^^^^....WWWWWWWW
WWWWWWWWWWWWWWWWWWWWWW......^^^......WWWWWWW
WWWWWWWWWWWWWWWWWWWWW..T.....^^^^..T.WWWWWWW
WWWWWWWWWWWWWWWWWWWWW........^^^^..T.WWWWWWW
WWWWWWWWWWWWWWWWWWWW........^^^....T.WWWWWWW
WWWWWWWWWWWWWWWWWWWW........^^^......WWWWWWW
WWWWWWWWWWWWWWWWWWWWWW.....^^^^.....WWWWWWWW
WWWWWWWWWWWWWWWWWWWWWW.....^^^......WWWWWWWW
WWWWWWWWWWWWWWWWWWWWWWW....^^......WWWWWWWWW
WWWWWWWWWWWWWWWWWWWWWW......^.....WWWWWWWWWW
WWWWWWWWWWWWWWWWWWWWW............WWWWWWWWWWW
WWWWWWWWWWWWWWWWWWWW....T......WWWWWWWWWWWWW
WWWWW...WWWWWWWWWWWWW..T.T.....WWWWWWWWWWWWW
WWWW..TTT.WWWWWWWWWWW...T.....WWWWWWWWWWWWWW
WWWWW.......WWWWWWWWWWW......WWWWWWWWWWWWWWW
WWWWWWWW...T.WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW
WWWWWWWWW....WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW
WWWWWWWWWW.T.WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW
WWWWWWWWWWW.WWWWWWWWWW.....WWWWWWWWWWWWWWWWW
WWWWWWWWWWWWWWWWWWWWW....T..WWWWWWWWWWWWWWWW
WWWWWWWWWWWWWWWWWWWWWWW.TTT..WWWWWWWWWWWWWWW
WWWWWWWWWWWWWWWWWWWWWWW..T..WWWWWWWWWWWWWWWW
WWWWWWWWWWWWWWWWWWWWWW...WWWWWWWWWWWWWWWWWWW
WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW
WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW
WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW""".split('\n')
# Now lst is a list of strings, but that doesn't matter
# because we can obtain characters in a string just like elements in a list
# duck typing FTW!
findCrosses(lst)
# Out: (21, 25)

I'm afraid the error you are getting is not caused by any of the code you have shared, your loop works perfectly well (other than line.split() splitting by whitespace which there is none in your file, you probably want list(line) or just line to split on every character)
This script runs without error demonstrating your issue is in some other part of your code:
import io
mock_file = io.StringIO("""WWWWWWWWWWWWWWWWWWWWWWW.TTT..^^^^...WWWWWWWW
WWWWWWWWWWWWWWWWWWWWWW...T..^^^^....WWWWWWWW
WWWWWWWWWWWWWWWWWWWWWW......^^^......WWWWWWW
WWWWWWWWWWWWWWWWWWWWW..T.....^^^^..T.WWWWWWW
WWWWWWWWWWWWWWWWWWWWW........^^^^..T.WWWWWWW
WWWWWWWWWWWWWWWWWWWW........^^^....T.WWWWWWW
WWWWWWWWWWWWWWWWWWWW........^^^......WWWWWWW
WWWWWWWWWWWWWWWWWWWWWW.....^^^^.....WWWWWWWW
WWWWWWWWWWWWWWWWWWWWWW.....^^^......WWWWWWWW
WWWWWWWWWWWWWWWWWWWWWWW....^^......WWWWWWWWW
WWWWWWWWWWWWWWWWWWWWWW......^.....WWWWWWWWWW
WWWWWWWWWWWWWWWWWWWWW............WWWWWWWWWWW
WWWWWWWWWWWWWWWWWWWW....T......WWWWWWWWWWWWW
WWWWW...WWWWWWWWWWWWW..T.T.....WWWWWWWWWWWWW
WWWW..TTT.WWWWWWWWWWW...T.....WWWWWWWWWWWWWW
WWWWW.......WWWWWWWWWWW......WWWWWWWWWWWWWWW
WWWWWWWW...T.WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW
WWWWWWWWW....WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW
WWWWWWWWWW.T.WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW
WWWWWWWWWWW.WWWWWWWWWW.....WWWWWWWWWWWWWWWWW
WWWWWWWWWWWWWWWWWWWWW....T..WWWWWWWWWWWWWWWW
WWWWWWWWWWWWWWWWWWWWWWW.TTT..WWWWWWWWWWWWWWW
WWWWWWWWWWWWWWWWWWWWWWW..T..WWWWWWWWWWWWWWWW
WWWWWWWWWWWWWWWWWWWWWW...WWWWWWWWWWWWWWWWWWW
WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW
WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW
WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW
W: WATER
T: TREE
.: GRASS
^: MOUNTAIN""")
def find_treasure(mapfile):
lst = []
with mapfile as rf:
for line in rf:
lst.append(list(line))
print(lst)
for i in range(len(lst)):
for j in range(len(lst[i])):
if lst[i][j] == 'T':
print('WHy')
else:
print('why am i here why')
find_treasure(mock_file)
Because of this I would verify that the lst variable is the same in the 2 mentioned sections of code, because range errors would only happen in something different from what you have shown.

Related

ValueError: invalid literal for int() after reading input into a tuple

I am writing a code that takes some numbers as tuple and then verify if there are numbers divisible by 3.
I am a beginner in python and just know some basic stuff about tuples. I have my code below:
def Div3and5():
data=tuple(input("Enter 3 numbers:"))
c=[]
a=0
for i in range(0,len(data)):
d=data[i]
c.append(d)
m=[int(x) for x in c]
print(m)
for i in m:
if m[i]%3==0:
print("It is not divisible")
Div3and5()
So, when I run this code I get an error which is:
ValueError: invalid literal for int() with base 10: ','
See, the values are stored as integers and when I give a command of printing c, it clearly shows all elements. Then, I try to convert each element to integers but it says error I don't know why. So, can you tell me the reason for that error. And also is there any straight-way for using this (divisibility) operation directly on tuples without converting them to list first.
Thanks
You are likely entering the numbers with spaces (or commas) in between. Hence, these spaces (or commas) make it into the tuple -- and can't be converted into ints.
Try instead, using str.split() to put the input numbers into a list.
def Div3and5():
c = input("Enter 3 numbers:").split(",")
# Gives you the list e.g. ["3", "4", "5"]
m = [int(x) for x in c]
# Gives you the list e.g. [3, 4, 5]
for i in m:
if i % 3 == 0:
print(f"{i} is divisible by 3")
Div3and5()
Remember that str.split() will accept a delimiter as an argument. In this case, I've put a comma ,, but you can have a space ' ' instead, depending on how your input should be entered by the user.
Note also, you were doing if m[i] % 3 == 0 in the if statement instead of if i % 3 == 0. This is not correct since i in each iteration of the loop is an element of the list m, and not an index.
Also, your condition i % 3 == 0 is such that if i is divisible by 3, then the print should indicate that the number is divisible -- you were printing that it's not divisible (probably a typo).
If you want all the numbers divisible by 3 and 5, you can change the condition like this:
if i % 3 == 0 and i % 5 == 0:
print(f"{i} is divisible by 3 and 5")
Here is the answer of your QUESTION :
def Div3and5():
c = input("Enter 3 numbers:")
list=c.split(",")
c=tuple(list)
m = [int(x) for x in c]
for i in m:
if i % 3 == 0:
print(f'{i} is is divisible by 3')
Div3and5()
#Enter 3 numbers with "," : 123,45,67

How can I take max value from some list but with some conditions?

list1 = [140,232,857,273,405,374,1234,394,1803]
u = 0
b = 4
for i in list1[u:b]
u+= 4
u+= 4
print(max(i))
Now I wanna take the max value from that list but only from list1[0:4] and continue with that.
Now I want to do something like it on this code:
for im in images:
ww, hh = zip(*(im.size for im in images))
www, hhh = im.size
max_h = max(hh)
y_test = []
try:
new_im.paste(im, (x_offset,y))
with open('x.txt', 'a') as file:
file.write(str(x_offset) + "\n")
with open('y.txt', 'a') as file:
file.write(str(y) + "\n")
with open('w.txt', 'a') as file:
file.write(str(www) + "\n")
with open('h.txt', 'a') as file:
file.write(str(hhh) + "\n")
x_offset += im.size[0]
if x_offset > int(q_w) - www:
print(max(hh))
x_offset =0
y += max(hhh)
if hh < y:
y += hhh
if hh > y:
y -= hhh
else:
y += max_h
except:
continue
if x_offset > int(q_w) - www then I want to take the max value of hhh until here.
How can I do that?
Please understand that we apply max( ... ) to a sequence,
rather than to a single scalar value,
e.g. max([6, 7, 8]) rather than max(4).
That first example was unclear.
I think your intent is to run a window of size k=4 over the list
and display local maxima.
A more natural way to express that, without incrementing u inside the loop,
would be:
for i in range(len(list1) - k):
window = list1[i : i + k]
print(i, max(window))
A very similar approach would apply to your second example.
Phrase the for loop in this way, and slice off k elements:
for i, im in enumerate(images):
if i + k < len(images):
window = images[i : i + k]
...
After that you're on your own,
do something useful with window,
as your question was unclear on details of what you want.
You wrote this line within the loop:
ww, hh = zip(*(im.size for im in images))
It computes the same thing each time, so to make things quicker
it belongs outside the loop.
Additionally, it trashes the im iteration variable,
so for the rest of the loop im is a constant value,
it is always the last element of images.
This seems Bad, it's probably not what you wanted.
Similarly, this is a constant
which could be hoisted outside the loop:
max_h = max(hh)
Also, your except: continue is correct,
but except: pass would be the more usual idiom,
expressing the intent to simply ignore the exception.
No statements follow it in the code you posted,
so both would work out the same.
Understand that continue would skip to top-of-loop,
skipping the following statements if there were any.

compair two files and display missing result

A list of IP addresses are downloaded to a file and rename to Old_file. As days goes by device get update with more IPs(or deleted). Therefore, I download a new list of IP addresses to another file named as New_file
I then want to run a compare these two files and see what is not matching
Old_file = [1.1.1.1,
1.1.1.2,
1.1.1.3,
1.1.1.4,
1.1.1.6,]
new_file = [1.1.1.1,
1.1.1.2,
1.1.1.3,
1.1.1.5,
1.1.1.6]
return needs to 1.1.1.4, and stops there. But never from Old_file e.g: 1.1.1.5 (we need the results only from the New_file only)
I really hope this would explain.
Thanks in advance
Tony
For a simple element-wise comparison, you could do
def get_first_unequal(s0, s1):
for e0, e1 in zip(s0, s1): # assumes sequences are of equal length!
if e0 != e1:
print(f"unequal elements: '{e0}' vs. '{e1}'!")
return (e0, e1)
return None # all equal
a = ['a', 'b', 'c']
b = ['a', 'b', 'd']
get_first_unequal(a, b)
# unequal elements: 'c' vs. 'd'!
# ('c', 'd')
# --> to get a list of all unequal pairs, you could also use
# [(e0, e1) for (e0, e1) in zip(s0, s1) if e0 != e1]
If you want to go more sophisticated, as mentioned in the comments, difflib might be your way to go. to run e.g. a comparison of two sequences (which are the list of strings you read from the two txt files you want to compare):
import difflib
a = ['a', 'b', 'c']
b = ['s', 'b', 'c', 'd']
delta = difflib.context_diff(a, b)
for d in delta:
print(d)
gives
*** 1,3 ****
! a
b
c
--- 1,4 ----
! s
b
c
+ d
to check the difference between two strings, you could do something like (borrowing from here):
a = 'string1'
b = 'string 2'
delta = difflib.ndiff(a, b)
print(f"a -> b: {a} -> {b}")
for i, d in enumerate(delta):
if d[0] == ' ': # no difference
continue
elif d[0] == '-':
print(f"Deleted '{d[-1]}' from position {i}")
elif d[0] == '+':
print(f"Added '{d[-1]}' to position {i-1}")
gives
a -> b: string1 -> string 2
Deleted '1' from position 6
Added ' ' to position 6
Added '2' to position 7
If you're assuming that both files should be exactly identical, you can just iterate over the characters of the first and compare them to the second. I.e.
# check that they're the same length first
if len(Old_file) != len(New_file):
print('not the same!')
else:
for indx, char in enumerate(Old_file):
try:
# actually compare the characters
old_char = char
new_char = New_file[indx]
assert(old_char == new_char)
except IndexError:
# the new file is shorter than the old file
print('not the same!')
break # kill the loop
except AssertionError:
# the characters do not match
print('not the same!')
break # kill the loop
It's worth noting that there are faster ways to do this. You could look into performing a checksum, though it wouldn't tell you which parts are different only that they are different. If the files are large, the performance of doing the check one character at a time will be quite bad -- in that case you can try instead to compare blocks of data at a time.
Edit: re-reading your original question, you could definitely do this with a while loop. If you did, I would suggest basically the same strategy of checking each individual character. In that case you would manually need to increment the indx of course.

I am confuse about this code can someone explain

Changing Duplicate characters in a string to ) and non duplicate to (.
I have tried 2 for loops but it doesn't work. I am beginner in coding therefore I cant understand this complex code can someone explain.
def duplicate_encode(word):
return (lambda w: ''.join(('(', ')')[c in w[:i] + w[i+1:]] for i, c in enumerate(w)))(word.lower())
print(duplicate_encode("rEcede"))
Input: "Mercedes Bench"
Output: ()())()((()()(
As said in a comment, I think this is bad coding practice and should be avoided. But it can serve as an example of code reading. So I'll give it a try here. (First you should read about lambda if you're not familiar with it.)
First, look at the matching parentheses and try to find the "deepest" parts:
The top one is: lambda w: ''.join(('(', ')')[c in w[:i] + w[i+1:]] for i, c in enumerate(w))) applied to word.lower().
Then we have ('(', ')')[c in w[:i] + w[i+1:]] for i, c in enumerate(w)) in place of three dots inside ''.join(...).
enumerate(w), where w is a string, will produce an enumerate object that can be iterated to get tuples of form (i,c), where i is the index of the letter c. Try running for x in enumerate(w): print(x) for different strings w in order to get a feel for it.
The ('(', ')')[c in w[:i] + w[i+1:]] for i, c in enumerate(w)) will then produce a generator object by iterating through the tuples of letters of w and the respective indices that will consist of only ')' and '(' that will be then concatenated by ''.join(...) into the final output string. Let's break it down further.
[c in w[:i] + w[i+1:]] will always evaluate to either [True] or [False] (see 6 as to why). Now, ('(', ')')[False] will return '(' and ('(', ')')[True] will return ')' (something I learned right now by typing it out to see what happens).
For any letter in w there will be a tuple in the generator object (see point 4), (i, c). The [c in w[:i] + w[i+1:]] will first take two substrings of w. The first one will include all the letters up to the position i (where the current letter is located) and the second will include all the letters after the current letter. These two substrings are then concatenated. Then c in part will just check if the current letter is in the resulting string, effectively checking if the letter c appears at some other part of the string as well. For example for a w = 'aba' and second tuple from enumerate('aba'), that is (1, 'b'), w[:i] will be equal to 'aba'[:1] which is 'a' and w[i+1:] will be equal to 'aba'[:1] which is equal to 'a', concatenated we get a string 'aa' and thus [c in w[:i] + w[i+1:]] which in this case is equal to ['b' in 'aa'] will evaluate to [False], hence resulting in '('.
Effectively the lambda part is just a function that for each letter at a given position, checks if the same letter is present in a modified string with the letter removed from that position. It is then applied to an argument word.lower() which just insures that the caps are ignored (e.g., 'A' and 'a' are counted as the same letter).
This code replicates exactly what the lambda function does. By separating the logic into distinct statements it is easier to follow the logic. Remove the comments from the print statements to see the whole process in detail.
def simple_duplicate_encode(word):
output = ""
for i, c in enumerate(word):
# print(i,c)
i1 = word[:i]
i2 = word[i+1:]
# print(":{} = {}".format(i, word[:i]))
# print("{}: = {}".format(i+1, word[i+1:]))
is_duplicated = c in i1 + i2 # Check to see if the character c is in the rest of the string
# print("Is duplicated:{}".format(is_duplicated))
character = ('(',')')[is_duplicated] # If is_duplicated = True the value is 1, else 0
# print(character)
output += character
return output

Python 3.xx - Deleting consecutive numbers/letters from a string

I actually need help evaluating what is going on with the code which I wrote.
It is meant to function like this:
input: remove_duple('WubbaLubbaDubDub')
output: 'WubaLubaDubDub'
another example:
input: remove_duple('aabbccdd')
output: 'abcd'
I am still a beginner and I would like to know both what is wrong with my code and an easier way to do it. (There are some lines in the code which were part of my efforts to visualize what was happening and debug it)
def remove_duple(string):
to_test = list(string)
print (to_test)
icount = 0
dcount = icount + 1
for char in to_test:
if to_test[icount] == to_test[dcount]:
del to_test[dcount]
print ('duplicate deleted')
print (to_test)
icount += 1
elif to_test[icount] != to_test[dcount]:
print ('no duplicated deleted')
print (to_test)
icount += 1
print ("".join(to_test))
Don't modify a list (e.g. del to_test[dcount]) that you are iterating over. Your iterator will get screwed up. The appropriate way to deal with this would be to create a new list with only the values you want.
A fix for your code could look like:
In []:
def remove_duple(s):
new_list = []
for i in range(len(s)-1): # one less than length to avoid IndexError
if s[i] != s[i+1]:
new_list.append(s[i])
if s: # handle passing in an empty string
new_list.append(s[-1]) # need to add the last character
return "".join(new_list) # return it (print it outside the function)
remove_duple('WubbaLubbaDubDub')
Out[]:
WubaLubaDubDub
As you are looking to step through the string, sliding 2 characters at a time, you can do that simply by ziping the string with itself shifted one, and adding the first character if the 2 characters are not equal, e.g.:
In []:
import itertools as it
def remove_duple(s):
return ''.join(x for x, y in it.zip_longest(s, s[1:]) if x != y)
remove_duple('WubbaLubbaDubDub')
Out[]:
'WubaLubaDubDub'
In []:
remove_duple('aabbccdd')
Out[]:
'abcd'
Note: you need itertools.zip_longest() or you will drop the last character. The default fillvalue of None is fine for a string.

Resources