how can I check a diagonal of my table for repeats? - python

I want to check if values in my table's diagonal are equal. How can I do that without checking each diagonal cell? I understand that I can use a loop to do that but I just can't figure out what loop to use.
table = [['1', ' ', '1'],
[' ', '1', ' '],
['1', ' ', '1']]
if tb[0][0] == tb[1][1] == tb[2][2] != ' ' or tb[-1][0] == tb[-2][1] == tb[-3][2] != ' ':
print(True)

Working with arrays and matrices is easiest with numpy. So if this is an option for you, this is how you could go about checking the diagonal of your table:
import numpy as np
table = [['1', ' ', '1'],
[' ', '1', ' '],
['1', ' ', '1']]
nptable = np.array(table)
# now we can simply get the unique values in the diagonal:
diag_values = np.unique(nptable.diagonal())
If you have a single value in diag_values then you know that all diagonal values are equal.
Now if you want to also check the other diagonal, you can use np.fliplr and redo the same:
diag_values = np.unique(np.fliplr(nptable).diagonal())
If you want to stick to lists then you could loop over the rows of table until you encounter a change if the value of the diagonal:
diag_val = table[0][0]
for i, row in enumerate(table):
if row[i] != diag_val: # row[i] is basically table[i][i]
print(f'diagonal value changes in row {i=}.')
break # we stop the loop as we encoutered a change
Checking the other diagonal is just as easy, simply access the element -i-1 instead of element i in each row:
diag_val = table[0][-1]
for i, row in enumerate(table):
if row[-i-1] != diag_val:
print(f'diagonal value changes in row {i=}.')
break # we stop the loop as we encoutered a change
Or, if the value in both cases should be the same, say diag_val='1', you can do it in one go:
diag_val = '1'
for i, row in enumerate(table):
if row[i] != diag_val or row[-i-1] != diag_val:
print(f'diagonal value changes in row {i=}.')
break # we stop the loop as we encoutered a change
Hope that helped!

One way is to do this is to extract the values of both diagonals as sets and then check if: a) the sets are equal and b) their size is 1.
main_diag = {row[ i] for i, row in enumerate(tb)}
anti_diag = {row[-i] for i, row in enumerate(tb, start=1)}
if main_diag == anti_diag and len(main_diag) == 1:
print('All values along both diagonals are the same.')

you can use numpy.diagonal() to get all the elements whether on the first or the second diagonal and then compare all the elements to satisfy the condition using numpy.all()
import numpy as np
mtx = np.array([['2', ' ', '1'],
[' ', '1', ' '],
['1', ' ', '3']])
first_diag = mtx.diagonal()
second_diag = (np.fliplr(mtx)).diagonal()
result = np.all(second_diag == '1')
if result:
print("all the elements in the diagonal are equal to one")
else:
print("not all elements in the diagonal are equal")

Related

Del list and next list element in list if string exist

I have an example:
list = [['2 a', 'nnn', 'xxxx','last'], ['next, next'], ['3', '4', 'next']]
for i in range(len(list)):
if list[i][-1] == "last":
del(list[i+1])
del(list[i])
I'd like to delete this list where the last item is "last" and the next item on the list.
In this example there is a problem every time - I tried different configurations, replacing with numpy array - nothing helps.
Trackback:
IndexError: list index out of range
I want the final result of this list to be ['3', '4', 'next']
Give me some tips or help how I can solve it.
Try this:
l = [['2 a', 'nnn', 'xxxx','last'], ['next, next'], ['3', '4', 'next']]
delete_next = False
to_ret = []
for x in l:
if x[-1] == 'last':
delete_next = True
elif delete_next:
delete_next = False
else:
to_ret.append(x)
Using a variable to store if this needs to be deleted
Loop over the list, if the last element of that iteration == 'last' then skip, else, append to a new list.
Also, it is not recommended to edit lists while iterating over them as strange things can happen, as mentioned in the comments above, like the indexes changing.
l = [['2 a', 'nnn', 'xxxx','last'], ['next, next'], ['3', '4', 'next']]
newlist = []
for i in l:
if i[-1] == 'last':
continue
else:
newlist.append(i)

How to access the elements between zero th index and date index from sublist in python3?

How to access the elements between zero th index and date index from sublist in python3?
Find element between zero th index and date index.
After that , concat those elements. and keep in a list.
After that insert the concat elements to first index in a sublist and remove splitted elements.
import re
nested_list =[["1","a","b","22/01/2014","variable"],["2","c","d"],
["3","e","f","23/01/2014","variable"]]
sub_list=[]
for i in range(0,len(nested_list)):
concat = ''
data_index = ''
for j in range(0,len(nested_list[i])):
temp = re.search("[\d]{1,2}/[\d]{1,2}/[\d]{4}", nested_list[i][j])
if temp:
date_index = j
if date_index:
for d in range(1,date_index):
concat = concat+' '+ nested_list[i][d]
print(concat)
Expected Output:
nested_list =[["1","a b","22/01/2014","variable"],["2","c","d"],["3","e f","23/01/2014","variable"]]
So you
want the elements between date and zeroth index thats why ["2","c","d"] i didnt combine these elemen t# Patrick Artner
Here you go:
import re
nested_list =[["1","a","b","22/01/2014"],["2","c","d"], ["3","e","f","23/01/2014"]]
result = []
for inner in nested_list:
if re.match(r"\d{1,2}/\d{1,2}/\d{4}",inner[-1]): # simplified regex
# list slicing to get the result
result.append( [inner[0]] + [' '.join(inner[1:-1])] + [inner[-1]] )
else:
# add as is
result.append(inner)
print(result)
Output:
[['1', 'a b', '22/01/2014'], ['2', 'c', 'd'], ['3', 'e f', '23/01/2014']]
Edit because dates might also occure in between - what was not covered by the original questions data:
import re
nested_list =[["1","a","b","22/01/2014"], ["2","c","d"],
["3","e","f","23/01/2014","e","f","23/01/2014"]]
result = []
for inner in nested_list:
# get all date positions
datepos = [idx for idx,value in enumerate(inner)
if re.match(r"\d{1,2}/\d{1,2}/\d{4}",value)]
if datepos:
# add elem 0
r = [inner[0]]
# get tuple positions of where dates are
for start,stop in zip([0]+datepos, datepos):
# join between the positions
r.append(' '.join(inner[start+1:stop]))
# add the date
r.append(inner[stop])
result.append(r)
# add anything _behind_ the last found date
if datepos[-1] < len(inner):
result[-1].extend(inner[datepos[-1]+1:])
else:
# add as is
result.append(inner)
print(result)
Output:
[['1', 'a b', '22/01/2014'],
['2', 'c', 'd'],
['3', 'e f', '23/01/2014', 'e f', '23/01/2014']]

Counting the number of consecutive 3s in a 2D list

My dataset which I imported into python as a list:
Is there a way I can count the largest number of consecutive 3s? Like in the first row, the output should be 5 as there are 5 consecutive 3s.
import csv
r = csv.reader(open('motor.csv'))
list_r = list(r)
for row in list_r:
print
count = 0
for col in row:
if col == '3' and row[row.index(col)+1] == '3':
count+=1
print count
This is the code I wrote but I seem to get incorrect output.
Consider using itertools.groupby to break the list into sub-sequences of identical values. Then simply return the maximum length of the sub-sequences.
from itertools import groupby
list_r = [
['3','3','3','3','3','1','3','3','5'],
['1','2','3','3','3','3','3','3','1','3','3','5','3'],
['3','2','3','3','3','3','3','3','1','3','3','5'],
]
result = [
max(len(list(g)) for k, g in groupby(row) if k == '3')
for row in list_r
]
assert result == [5, 6, 6]
They to use the following as a guide:
import itertools
def consecutive(group):
first, second = itertools.tee(group)
second.next()
for first, second in itertools.izip(first, second):
if second != first + 1: return False
return True
def iterate_submatrix(matrix, t, l):
'''yield the horizontals and diagonals of 4x4 subsection of matrix starting at t(op), l(eft) as 4-tuples'''
submat = [row[l:l+4] for row in matrix[t:t+4]]
for r in submat: yield tuple(r)
for c in range (0,4):
yield tuple(r[c] for r in submat)
yield tuple(submat[rc][rc] for rc in range (0,4))
yield tuple(submat[rc][3-rc] for rc in range(0,4))
for item in iterate_submatrix(test_matrix, 0,0):
print item, consecutive(item)
First, row.index(col) will always produce the index of the first value of col in the row. This is clearly not what was intended. Instead, I'd recommend using enumerate to iterate over the values and indices in the row at the same time.
Second, you are only tracking the current number of consecutive 3's, and there is no code to track the maximum of this count value. Adding another variable and an else clause to your code can resolve this.
for row in list_r:
max_count = current_count = 0
for index, value in enumerate(row[:-1]):
if value == '3' and row[index+1] == '3':
current_count += 1
else:
max_count = max(current_count, max_count)
current_count = 0
print count
import re
data = [
['1', '2', '2', '3', '5', '6'],
['1', '2', '3', '3', '4', '5'],
['1', '2', '3', '3', '3', '4']
]
max = 0
for item in data:
match = re.search(r'3+', "".join(item))
try:
if len(str(match.group(0))) > max:
max = len(str(match.group(0)))
except AttributeError:
pass
print(max)

Combine elements of a list with all possible separators

I have the following requirement.
I have a list which say has 3 elements [X,Y,2]
What I would like to do is to generate strings with a separator (say "-") between (or not) each element. The order of the elements in the array should be preserved.
So the output would be:
'XY2'
'X-Y-2'
'X-Y2'
'XY-2'
is there an elegant way to this in python?
>>> import itertools
>>> for c in itertools.product(' -', repeat=2): print ('X%sY%s2' % c).replace(' ', '')
XY2
XY-2
X-Y2
X-Y-2
Or, with the elements coming from a python list:
import itertools
a = ['X', 'Y', 2]
for c in itertools.product(' -', repeat=2):
print ('%s%s%s%s%s' % (a[0],c[0],a[1],c[1],a[2])).replace(' ', '')
Or, in a slightly different style:
import itertools
a = ['X', 'Y', '2']
for c in itertools.product(' -', repeat=2):
print ( '%s'.join(a) % c ).replace(' ', '')
To capture the output to a list:
import itertools
a = ['X', 'Y', '2']
output = []
for c in itertools.product(' -', repeat=len(a)-1):
output.append( ('%s'.join(a) % c).replace(' ', '') )
print 'output=', output
A little more generalized but works for any number of separators and hopefully is easy to understand at each step:
import itertools
a = ['X', 'Y', '2']
all_separators = ['', '-', '+']
results = []
# this product puts all separators in all positions for len-1 (spaces between each element)
for this_separators in itertools.product(all_separators, repeat=len(a)-1):
this_result = []
for pair in itertools.izip_longest(a, this_separators, fillvalue=''):
for element in pair:
this_result.append(element)
# if you want it, here it is as a comprehension
# this_result = [element for pair
# in itertools.izip_longest(a, this_separators, fillvalue='')
# for element in pair]
this_result_string = ''.join(this_result) # check out join docs if it's new to you
results.append(this_result_string)
print results
>>> ['XY2', 'XY-2', 'XY+2', 'X-Y2', 'X-Y-2', 'X-Y+2', 'X+Y2', 'X+Y-2', 'X+Y+2']
These are the results for your case with just '' and '-' as separators:
>>> ['XY2', 'XY-2', 'X-Y2', 'X-Y-2']
If you want everything in one comprehension:
results = [''.join(element for pair
in itertools.izip_longest(a, this_separators, fillvalue='')
for element in pair)
for this_separators in itertools.product(all_separators, repeat=len(a)-1)]
I don't know if there is a function in itertool in order to do that. But i always think it's fun and a good exercice to do this kind of things. So there is a solution with recursive generator :
def generate(liste):
if len(liste) == 1:
yield [liste]
else:
for i in generate(liste[1:]):
yield [[liste[0]]]+i
yield [ [liste[0]]+i[0] ] + i[1:]
if __name__ == "__main__":
for i in generate (["X","Y","2"]):
print "test : " + str(i)
if len(i) == 1:
print "".join(i[0])
else:
print reduce(
lambda left, right : left + "".join(right),
i,
"")
Something like this?
from itertools import permutations
i = ["X","Y","2"]
for result in permutations(i, 3):
print "-".join(result)
Result:
X-Y-2
X-2-Y
Y-X-2
Y-2-X
2-X-Y
2-Y-X

Learning Python: Changing value in list based on condition

Sorry for the very basic question, but this is actually a 2-part question:
Given a list, I need to replace the values of '?' with 'i' and the 'x' with an integer, 10. The list does not always have the same number of elements, so I need a loop that permits me to do this.
a = ['1', '7', '?', '8', '5', 'x']
How do I grab the index of where the value is equal to '?'. It'd be nice if this show me how I could grab all the index and values in a list as well.
Write a function for it and use map() to call it on every element:
def _replaceitem(x):
if x == '?':
return 'i'
elif x == 'x':
return 10
else:
return x
a = map(_replaceitem, a)
Note that this creates a new list. If the list is too big or you don't want this for some other reason, you can use for i in xrange(len(a)): and then update a[i] if necessary.
To get (index, value) pairs from a list, use enumerate(a) which returns an iterator yielding such pairs.
To get the first index where the list contains a given value, use a.index('?').
For 1:
for i in range(len(a)):
if a[i] == '?':
a[i] = 'i'
elif a[i] == 'x':
a[i] = 10
For 2, what do you mean by "key"? If you mean index:
index = a.index('?')
Only because no one's mentioned it yet, here's my favourite non-for-loop idiom for performing replacements like this:
>>> a = ['1', '7', '?', '8', '5', 'x']
>>> reps = {'?': 'i', 'x': 10}
>>> b = [reps.get(x,x) for x in a]
>>> b
['1', '7', 'i', '8', '5', 10]
The .get() method is incredibly useful, and scales up better than an if/elif chain.
Start by reading the Built-in Types section of the Library Reference. I think that you are looking for list.index.
it is function called 'index':
>>> a = ['1', '7', '?', '8', '5', 'x']
>>> a.index('?')
2
You can now use lambda
# replace occurrences of ?
a = map(lambda x: i if x == '?' else x, a)
# replace occurrences of x
a = list(map(lambda x: 10 if x == 'x' else x, a))
a = ['1', '7', '?', '8', '5', 'x']
for index, item in enumerate(a):
if item == "?":
a[index] = "i"
elif item == "x":
a[index = 10
print a

Categories