Alphabetical Grid using python3 - python

how to write a function grid that returns an alphabetical grid of size NxN, where a = 0, b = 1, c = 2.... in python
example :
a b c d
b c d e
c d e f
d e f g
here I try to create a script using 3 for loops but it's going to print all the alphabets
def grid(N):
for i in range(N):
for j in range(N):
for k in range(ord('a'),ord('z')+1):
print(chr(k))
pass

Not the most elegant, but gets the job done.
import string
def grid(N):
i = 0
for x in range(N):
for y in string.ascii_lowercase[i:N+i]:
print(y, end=" ")
i += 1
print()
grid(4)
Output
a b c d
b c d e
c d e f
d e f g

Extending from #MichHeng's suggestion, and using list comprehension:
letters = [chr(x) for x in range(ord('a'),ord('z')+1)]
def grid(N):
for i in range(N):
print(' '.join([letters[i] for i in range(i,N+i)]))
grid(4)
output is
a b c d
b c d e
c d e f
d e f g

You have specified for k in range(ord('a'),ord('z')+1) which prints out the entire series from 'a' to 'z'. What you probably need is a reference list comprehension to pick your letters from, for example
[chr(x) for x in range(ord('a'),ord('z')+1)]
Try this:
letters = [chr(x) for x in range(ord('a'),ord('z')+1)]
def grid(N):
for i in range(N):
for j in range(i, N+i):
print(letters[j], end=' ')
if j==N+i-1:
print('') #to move to next line
grid(4)
Output
a b c d
b c d e
c d e f
d e f g
Do you need to add a check for N<=13 ?

Related

How to print a 1x2 list from 2 separate lists?

I need to print 2 entries from list 2 for every one entry in list 1
So say
ll = "1,2,3,4,5,6,7,8,9"
l2 = "a,b,c,d,e,f,g,h,i"
I need to print
1 a b
2 c d
3 d e
4 f g
5 h i
and so on
I can do
for i,j in zip(matches,matches2):
print (i,j)
but this just prints
1 a
2 b
3 c
4 d
but i can't work out how to print 2 entries from matches2 for every 1 entry in matches
You can create an iterator from matches2 so that it can be extracted twice for each iteration with zip:
iter2 = iter(matches2)
for i, j, k in zip(matches, iter2, iter2):
print(i, j, k)
Using your first example strings you can do something like this:
ll = "1,2,3,4,5,6,7,8,9".split(',')
l2 = "a,b,c,d,e,f,g,h,i".split(',')
for i in range(0,len(ll)):
j=i*2
if j+1<len(l2):
print(ll[i],l2[j],l2[j+1])

Trying to verify last position of a string

Im trying to verify if the last char is not on my list
def acabar_char(input):
list_chars = "a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 1 2 3 4 5 6 7 8 9 0".split()
tam = 0
tam = (len(input)-1)
for char in input:
if char[tam] in list_chars:
return False
else:
return True
When i try this i get this error:
if char[tam] in list_chars:
IndexError: string index out of range
you can index from the end (of a sting or a list) with negative numbers
def acabar_char(input, list_cars):
return input[-1] is not in list_chars
It seems that you are trying to assert that the last element of an input string (or also list/tuple) is NOT in a subset of disallowed chars.
Currently, your loop never even gets to the second and more iteration because you use return inside the loop; so the last element of the input only gets checked if the input has length of 1.
I suggest something like this instead (also using the string.ascii_letters definition):
import string
DISALLOWED_CHARS = string.ascii_letters + string.digits
def acabar_char(val, disallowed_chars=DISALLOWED_CHARS):
if len(val) == 0:
return False
return val[-1] not in disallowed_chars
Does this work for you?
you are already iterating through your list in that for loop, so theres no need to use indices. you can use list comprehension as the other answer suggest, but I'm guessing you're trying to learn python, so here would be the way to rewrite your function.
list_chars = "a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 1 2 3 4 5 6 7 8 9 0".split()
for char in input:
if char in list_chars:
return False
return True
list_chars = "a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 1 2 3 4 5 6 7 8 9 0".split()
def acabar_char(input):
if input in list_chars:
print('True')

code not running as aspected given wrong result

I want to print
A
B C
C D E
E F G H
I tried but showing the result
A
B C
C D D
D E E E
a = chr(65)
for i in range(0, 4):
i = i + 1
for j in range(65, 65+i):
print(a, end=" ")
a = chr(65 + i)
print("\n")
Make it simple:
letter_a_code = ord('A')
for i in range(4):
for j in range(i+1):
letter = chr(letter_a_code+j+i)
print(letter, end=" ")
print()
prints:
A
B C
C D E
D E F G
You have to print 4 rows. i is your index.
Each row is made of i elements.
Add the offset for letter A code (don't hardcode it, use ord('A')): done.

Optimizing pandas filter inside apply function

I have a list of pairs--stored in a DataFrame--each pair having an 'a' column and a 'b' column. For each pair I want to return the 'b's that have the same 'a'. For example, given the following set of pairs:
a b
0 c d
1 e f
2 c g
3 e h
4 i j
5 e k
I would like to end up with:
a b equivalents
0 c d [g]
1 e f [h, k]
2 c g [d]
3 e h [f, k]
4 i j []
5 e k [h, e]
I can do this with the following:
def equivalents(x):
l = pairs[pairs["a"] == x["a"]]["b"].tolist()
return l[1:] if l else l
pairs["equivalents"] = pairs.apply(equivalents, axis = 1)
But it is painfully slow on larger sets (e.g. 1 million plus pairs). Any suggestions how I could do this faster?
I think this ought to be a bit faster. First, just add them up.
df['equiv'] = df.groupby('a')['b'].transform(sum)
a b equiv
0 c d dg
1 e f fhk
2 c g dg
3 e h fhk
4 i j j
5 e k fhk
Now convert to a list and remove whichever letter is already in column 'b'.
df.apply( lambda x: [ y for y in list( x.equiv ) if y != x.b ], axis=1 )
0 [g]
1 [h, k]
2 [d]
3 [f, k]
4 []
5 [f, h]

Why write() method writes unknown characters?

I have this simple txt file:
[header]
width=8
height=5
tilewidth=175
tileheight=150
[tilesets]
tileset=../GFX/ts1.png,175,150,0,0
[layer]
type=Tile Layer 1
data=
1,1,1,1,1,1,1,1,
1,0,0,0,0,0,0,1,
1,0,0,0,0,1,1,1,
1,0,0,0,6,0,0,1,
1,1,1,1,4,1,1,1
I want to separate the text by the "[header]", "[tilesets]" and "[layers]". Problem is, if I split it in this way:
m = open(self.fullPath, 'r+')
sliced = m.read().split() # Default = \n
print sliced
It shall separate each line, because read() always leave a '\n' at the end of every line:
['[header]', 'width=8', 'height=5', 'tilewidth=175', 'tileheight=150', '[tilesets]', 'tileset=../GFX/ts1.png,175,150,0,0', '[layer]', 'type=Tile', 'Layer', '1', 'data=', '1,1,1,1,1,1,1,1,', '1,0,0,0,0,0,0,1,', '1,0,0,0,0,1,1,1,', '1,0,0,0,6,0,0,1,', '1,1,1,1,4,1,1,1']
But it's possible to split perfectly if, instead a new-line-character, there was a "#" sign or whatever separating each section.
Then, I thought: "There are empty lines there, and they are new-line-characters, so I just need to test if the line equals to the new-line-character and replace it with '#'":
for line in m.readlines():
if line == '\n':
m.write('#')
for line in m.readlines():
print line
Perfect.. Except that.. Instead of achieving this:
[header]
width=8
height=5
tilewidth=175
tileheight=150
#
[tilesets]
tileset=../GFX/ts1.png,175,150,0,0
#
[layer]
type=Tile Layer 1
data=
1,1,1,1,1,1,1,1,
1,0,0,0,0,0,0,1,
1,0,0,0,0,1,1,1,
1,0,0,0,6,0,0,1,
1,1,1,1,4,1,1,1
I get this:
[header]
width=8
height=5
tilewidth=175
tileheight=150
[tilesets]
tileset=../GFX/ts1.png,175,150,0,0
[layer]
type=Tile Layer 1
data=
1,1,1,1,1,1,1,1,
1,0,0,0,0,0,0,1,
1,0,0,0,0,1,1,1,
1,0,0,0,6,0,0,1,
1,1,1,1,4,1,1,1##õÙÓ Z d Z d d l Z d d l Z d " Z d $ „ Z d - f d „ ƒ Y Z e H d ƒ Z e I j ƒ Æ Çîà  õÙÓ ; | j d ƒ } i < g d 6 g d 6 g d 6 } d = d d g } x 0 ·ð? | j ƒ D u tîà  õÙÓI À¶ð ) (–à W # "íà  õ#ÎÔ €·ðB | j ƒ D ú ú–à  õ(Tò `·ð } | C G H q | #·ð Ñ Ñ–à  õ#ÎÔ ¨ ¨–à  õ#ÎÔ
E G H | F j ƒ –à  õ#ÎÔ S V V–à  õ#ÎÔž ÿÿÿÿ t | j d ƒ } i g d 6g d 6g d 6} d d d g } x0 | j ƒ D]" } | d k rk | j d ƒ n qI Wx | j ƒ D] } | GHq| Wd
GH| j ƒ d S `:ð> >§à  õ#ÎÔÀ:ðà¢îðà:ð ;ð`ßî ;ð#;ð0ð`;ð £îXð# ï€;ð€ð ;ð`£îÀ;ðà;ð ð2 2›à  õ#ÎÔ`<ð€<ðà¤î <ð ?îÀ<ðà<ð =ð =ð#=ðÀ?î ïÐð`=ð¸ï€=ð =ðøðÀ=ðà=ð >ð >ð#>ð`>ð ð€>ð >ðÀ>ðà>ð ?ð#OÑ ?ð#?ð`?ð€?ð ?ðHðpðÀ?ð˜ðÀðà?ð #ðÀ£î##ð`#ð€#ð #ð PðHPðÀ#ðà#ð
It makes no sense :).
Simultaneously reading from and writing to a file tends to have unpredictable effects on what kind of output you get.
If your categories are always separated by two newlines, then just split on that, instead of doing any fancy find/replace operations.
m = open("input.txt", "r+")
sliced = m.read().split("\n\n")
print "data has been split into {} categories.".format(len(sliced))
#print the starting line of each category
for category in sliced:
print category.split("\n")[0]
Result:
data has been split into 3 categories.
[header]
[tilesets]
[layer]

Categories