How to fill a Python numpy chararray with spaces? - python

For some reason I'm struggling to initialize a numpy.chararray with spaces.
This works:
char_array1 = np.chararray((3, 3))
char_array1[:] = 'a'
char_array1
Output:
chararray([['a', 'a', 'a'],
['a', 'a', 'a'],
['a', 'a', 'a']],
dtype='|S1')
This doesn't:
char_array2 = np.chararray((3, 3))
char_array2[:] = ' '
char_array2
Output:
chararray([['', '', ''],
['', '', ''],
['', '', '']],
dtype='|S1')
What is causing this? I can't see an option to strip the items or something.

In fact char arrays do remove whitespace:
Versus a regular NumPy array of type str or unicode, this class adds
the following functionality:
values automatically have whitespace removed from the end when indexed
comparison operators automatically remove whitespace from the end when
comparing values vectorized string operations are provided as methods
(e.g. endswith) and infix operators (e.g. "+", "*", "%")
So the answer is use a regular array of type str or unicode:
char_array3 = np.empty((3, 3), dtype='str')
char_array3[:] = ' '
char_array3
Output:
array([[' ', ' ', ' '],
[' ', ' ', ' '],
[' ', ' ', ' ']],
dtype='|S1')

Just create your array with ndarray:
chararray = np.ndarray((3,3), dtype='S1')
chararray[:]=' '
gives:
array([[' ', ' ', ' '],
[' ', ' ', ' '],
[' ', ' ', ' ']],
dtype='|S1')

Related

Adding Adjacent Numbers in a Python String

I am attempting to code a FEN number calculator based on a board:
boardPeices = ['br', 'bn', 'bb', 'bq', 'bk', 'bb', 'bn', 'br',
'bp', 'bp', 'bp', 'bp', 'bp','bp', 'bp', 'bp',
' ', ' ', ' ', ' ', ' ',' ', ' ', ' ',
' ', ' ', ' ', ' ', ' ',' ', ' ', ' ',
' ', ' ', ' ', ' ', ' ',' ', ' ', ' ',
' ', ' ', ' ', ' ', ' ',' ', ' ', ' ',
'wp', 'wp', 'wp', 'wp', 'wp','wp', 'wp', 'wp',
'wr', 'wn', 'wb', 'wq', 'wk','wb', 'wn', 'wr',
]
and have gotten pretty far, to where I have 8 stings, each with a row of the FEN number. Currently, the below code prints this: rnbqkbnr/pppppppp/11111111/11111111/11111111/11111111/PPPPPPPP/RNBQKBNR
print(f'{fenRow1}/{fenRow2}/{fenRow3}/{fenRow4}/{fenRow5}/{fenRow6}/{fenRow7}/{fenRow8}')
The problem is, the FEN number's ones should be concentrated into 8's, as there are 8 numbers next to each other. Due to everything being in strings, I cannot figure out how to add the 8 numbers together, in a way that a different position would still work, where the numbers are separated (ie, after e4)
You can use itertools.groupby:
from itertools import groupby
s = 'rnbqkbnr/pppppppp/11111111/11111111/11111111/11111111/PPPPPPPP/RNBQKBNR'
out = ''.join([x for k, g in groupby(s, lambda x: x=='1')
for x in ([str(len(list(g)))] if k else list(g))])
Output:
'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR'
Example on another input (s = 'rnbqkbnr/ppp1pppp/111p1111/11111111/11111111/11111111/PPPPPPPP/RNBQKBNR'):
'rnbqkbnr/ppp1pppp/3p4/8/8/8/PPPPPPPP/RNBQKBNR'
Use short regex substitution:
import re
s = 'rnbqkbnr/pppppppp/11111111/11111111/11111111/11111111/PPPPPPPP/RNBQKBNR'
new_s = re.sub(r'\d{2,}', lambda m: str(len(m.group())), s)
rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR

Extract all element of a list that matched a string

I have a keyword list and an input list of lists. My task is to find those lists that contain the keyword (even partially). I am able to extract the lists that contain the keyword using the following code:
t_list = [['Subtotal: ', '1,292.80 '], ['VAT ', ' 64.64 '], ['RECEIPT TOTAL ', 'AED1,357.44 '],
['NOT_SELECTED, upto2,000 ', 'Sub total ', '60.58 '],
['NOT_SELECTED, upto500 ', 'amount 160.58 ', '', '3.03 '],
['Learn', 'Bectricity total ', '', '', '63.61 ']]
keyword = ['total ', 'amount ']
for lists in t_list:
for string_list in table:
string_list[:] = [item for item in string_list if item != '']
for element in string_list:
element = element.lower()
if any(s in element for s in keyword):
print(string_list)
The output is:
[['Subtotal: ', '1,292.80 '], ['RECEIPT TOTAL ', 'AED1,357.44 '], ['NOT_SELECTED, upto2,000 ', 'Sub total ', '60.58 '], ['NOT_SELECTED, upto500 ', 'amount 160.58 ', '3.03 '],
['Learn', 'Bectricity total ', '63.61 ']]
Required output is to have only the string that matched with the keyword and the number in the list.
Required output:
[['Subtotal: ', '1,292.80 '], ['RECEIPT TOTAL ', 'AED1,357.44 '], ['Sub total ', '60.58 '], ['amount 160.58 ', '3.03 '],['Bectricity total ', '63.61 ']]
If I can have the output as a dictionary with the string matched to the keyword as key and the number a value, it would be perfect.
Thanks a ton in advance!
Here is the answer from our chat, slightly modified with some comments as some explanation for the code. Feel free to ask me to clarify or change anything.
import re
t_list = [
['Subtotal: ', '1,292.80 '],
['VAT ', ' 64.64 '],
['RECEIPT TOTAL ', 'AED1,357.44 '],
['NOT_SELECTED, upto2,000 ', 'Sub total ', '60.58 '],
['NOT_SELECTED, upto500 ', 'amount 160.58 ', '', '3.03 '],
['Learn', 'Bectricity total ', '', '', '63.61 ']
]
keywords = ['total ', 'amount ']
output = {}
for sub_list in t_list:
# Becomes the string that matched the keyword if one is found
matched = None
for item in sub_list:
for keyword in keywords:
if keyword in item.lower():
matched = item
# If a match was found, then we start looking at the list again
# looking for the numbers
if matched:
for item in sub_list:
# split the string so for example 'amount 160.58 ' becomes ['amount', '160.58']
# This allows us to more easily extract just the number
split_items = item.split()
for split_item in split_items:
# Simple use of regex to match any '.' with digits either side
re_search = re.search(r'[0-9][.][0-9]', split_item)
if re_search:
# Try block because we are making a list. If the list exists,
# then just append a value, otherwise create the list with the item
# in it
try:
output[matched.strip()].append(split_item)
except KeyError:
output[matched.strip()] = [split_item]
print(output)
You mentioned wanting to match a string such as 'AED 63.61'. My solution is using .split() to separate strings and make it easier to grab just the number. For example, for a string like 'amount 160.58' it becomes much easier to just grab the 160.58. I'm not sure how to go about matching a string like the one you want to keep but not matching the one I just mentioned (unless, of course, it is just 'AED' in which case we could just add some more logic to match anything with 'aed').

Mutating two dimensional list

I'm Trying to make a more advanced Tic Tac Toe program with an 'infinite' amount of lines/rows.
But when I try to mutate the list, it changes the whole column instead of just one spot.
size = 4
board = size * [size*[' ']]
board[0][1] = 'x'
#output:
#[[' ', 'x', ' ', ' '],
# [' ', 'x', ' ', ' '],
# [' ', 'x', ' ', ' '],
# [' ', 'x', ' ', ' ']]
How can I fix that?
It occurs because the inner list each row is made of is the same object that gets repeated.
You can change it to
board = [
[' ']*size
for _ in range(size)
]
Or use a double list comprehension
size = 4
board = [
[' ' for _ in range(size)]
for _ in range(size)
]
board[0][1] = 'x'
print(board)
which both produce
[[' ', 'x', ' ', ' '], [' ', ' ', ' ', ' '], [' ', ' ', ' ', ' '], [' ', ' ', ' ', ' ']]
Kudos to #Pynchia for beating me to the answer. Here is my version of code. I think the problem you were having was a result of your method of creating a list of lists.
size = 4
# simple way to create a list of lists
board = [size * [' '] for i in range(4)]
board[0][1] = 'x'
print(board)
Output will be as expected.

Use Python to match a letter in a string only when followed by a space, period, or nothing, without regex?

I am trying to write this code for readability but the last 'for x in measurements' clearly doesn't work.
The following prints ' t' but I don't want it to match on ' test'
I do want it to match on ' t' of 'this is a t' if it were a test case.
Possible without resorting to regex?
measurements = ['t', 'tsp', 'T', 'tbl', 'tbs', 'tbsp', 'c']
measurements = ([' ' + x + ' ' for x in measurements] + #space on either side
[' ' + x + '.' for x in measurements] + #space in front, period in back
[' ' + x + '' for x in measurements]) #space in front, nothing in back???
string_to_check = 'this is a test'
for measurement in measurements:
if measurement in string_to_check:
print(measurement)
Here you could use re.search
>>> measurements = ['t', 'tsp', 'T', 'tbl', 'tbs', 'tbsp', 'c']
>>> measurements = ([' ' + x + ' ' for x in measurements] + [' ' + x + '\.' for x in measurements] + [' ' + x + r'\b' for x in measurements])
>>> measurements
[' t ', ' tsp ', ' T ', ' tbl ', ' tbs ', ' tbsp ', ' c ', ' t\\.', ' tsp\\.', ' T\\.', ' tbl\\.', ' tbs\\.', ' tbsp\\.', ' c\\.', ' t\\b', ' tsp\\b', ' T\\b', ' tbl\\b', ' tbs\\b', ' tbsp\\b', ' c\\b']
>>> string_to_check = 'this is a test'
>>> for measurement in measurements:
if re.search(measurement, string_to_check):
print(measurement)
>>>
I had done two things here.
[' ' + x + '\.' for x in measurements], escape the dot in-order to match a literal dot, since dot is a special meta character in regex which matches any character.
[' ' + x + r'\b' for x in measurements] add word boundary \b, since \b matches between a word character and a non-word character, it won't pick spacet from <space>test
The problem is that you're coded for a different meaning of 'nothing behind it' than you're thinking of.
You've included the string ' t' in your array which is a substring of the string 'this is a test' [namely, it's sitting there at the front of the word test].
If you want 'nothing behind it' to mean 'at the end of the string' then you'll have to check what's at the end of the string instead of using substring search.
measurements
[' t ', ' tsp ', ' T ', ' tbl ', ' tbs ', ' tbsp ', ' c ', ' t.', ' tsp.', ' T.', ' tbl.', ' tbs.', ' tbsp.', ' c.', ' t', ' tsp', ' T', ' tbl', ' tbs', ' tbsp', ' c']
You can find ' t' in measurements.So ' t' in your check string "this is a[ t]est".
so, it's right to return ' t'.
if you want to exactly match ' t' not ' txxx', you need to
[' ' + x + r'\b' for x in measurements]
A possible non-regex approach is to split string_to_check into a list of words. Then in will look for a word that matches exactly.
measurements = ['t', 'tsp', 'T', 'tbl', 'tbs', 'tbsp', 'c']
string_to_check = 'this is a test'
words_to_check = string_to_check.replace('.', ' ').split()
for measurement in measurements:
if measurement in words_to_check:
print(measurement)

appending 2 lists at the same time

I have a function that draws rectangles:
def drawTbl(l, w):
ln1 = ' '
ln2 = '-'
ln3 = '|'
x = range(l)
print '+', ln2*w, '+'
for i in range(len(x)):
print ln3, ln1*w, ln3
print '+', ln2*w, '+'
It works fine, but I'm attempting to kind of graph this (this is like a pong clone) so that I can place a ball 'O' at the center and use X and Y for collision detection. When I use this function:
def tblData(l, w):
table=[]
for x in range(l):
table.append([])
for y in range(w):
table.append([])
It does seem to append the blank lists, but when I try to use table[x][y], all I receive is an error.
When I return table from tblData, I do get a list of empty lists,
but say (l, w) is (12, 56), so I'm trying to place ball 'O' at the center of the grid (6, 28), simply typing table[6][28] returns an error, so I don't know how I would append 'O' to table[6,28]
So my question is, how can I effectively access list[x][y]?
Instead of creating empty lists you will need to initialize the values in the inner lists to some reasonable value, like a space.
For example:
def tblData(l, w):
table=[]
for x in range(l):
table.append([' '] * w)
return table
Or more concisely:
def tblData(l, w):
return [[' '] * w for x in range(l)]
Note that [' '] * 3 creates the list [' ', ' ', ' '], so [' '] * w is equivalent to
[' ' for x in range(w)].
For example:
>>> import pprint
>>> table = [[' '] * 4 for x in range(5)]
>>> pprint.pprint(table)
[[' ', ' ', ' ', ' '],
[' ', ' ', ' ', ' '],
[' ', ' ', ' ', ' '],
[' ', ' ', ' ', ' '],
[' ', ' ', ' ', ' ']]
>>> table[3][1] = 'O'
>>> pprint.pprint(table)
[[' ', ' ', ' ', ' '],
[' ', ' ', ' ', ' '],
[' ', ' ', ' ', ' '],
[' ', 'O', ' ', ' '],
[' ', ' ', ' ', ' ']]

Categories

Resources