Accessing dictionary key with multiple values - python

I have an assignment and for the first part, I am to access a text file which will have a list of production rules. I created a list of dictionaries from this text file:
x = y
x = y x
y = 0
y = 1
that looks like this:
myList = [{'x': 'y'}, {'x':'y x'}, {'y': 0}, {'y': 1}]
I want to find all the possible outputs when applying these rules. I am going to attempt to write code later that will go through and replace the nonterminal values and output a bunch of binary. However, for this dictionary:
{'x': 'y x'}
'y x' is all one string so I cannot replace y or x with anything unless I explicitly say
'y x' = some value
I have written this code and written a really bad test code to see if the computer can see if a value for a key exists:
prodList = []
for line in open('name of file', "r"):
line = line.strip()
lhs, rhs = line.split(' = ')
myList.append({lhs:rhs})
if 'y' in myList[0].values():
print True
Now if I run this it will print True and I could move on, but I can't seem to write code where if I wrote:
if 'y' in myList[1].values():
print True
that it would be True.
I tried writing
myList.append({lhs:rhs.split()})
But that didn't help and I couldn't check for any values at all. Is there any way that I could have the list look like this:
myList = [{'x': 'y'}, {'x':'y', x'}, {'y': 0}, {'y': 1}]
So that if I wrote
if 'y' in myList[1].values():
print True
it would return True?
If this sounds confusing, please let me know so I can try to clarify more.
I also tried to make a dictionary instead of a list of dictionaries by doing this:
for line in open('file.txt', "r"):
line = line.strip()
lhs, rhs = line.split(' = ')
myDict[lhs] = rhs
but when I printed the dictionary, I only got this:
{'y': 1, 'x': 'x y'}
I'm sure there is a better way to do this but I can't seem to figure out a way that works.
I looked over the above code again and I was just looking at the list of values and not the values themselves.
My question now is how do I make the dictionary with multiple values for one key? When I run this code:
for line in open(fileName, "r"):
line = line.strip()
lhs, rhs = line.split(' = ')
prodList[lhs] = rhs.split()
print prodList
I end up with just this:
{'y': [1], 'x': ['y', 'x']}
I'm not sure as to how I get this
myList = {'x': ['y'], 'x':['y', 'x'], 'y': [0], 'y':[1]}

Related

Why do I get Type Error on one line, but not the others

So, I have this piece of code which is used to add/subtract from the x and y value in a list with dictionaries. The thing is, the code must account for the fact that the dictionary can be given like a string with quotes around it. So, for that reason I use ast.literal_eval(point) to turn the string into a dictionary. However, for some reason with this line that has been changed following commands don't work like they do with the others.
Commands in question: point['x'] += offset['x'] and point['y'] += offset['y']
I am very confused, both with the issue in question and the code in general as it was translated from js.
import ast
def parse(point):
if type(point) == dict:
return point
else:
return ast.literal_eval(point)
def shift(offset, points):
modified_points = points.copy()
for point in modified_points:
arg_type = type(point)
parse(point)
point['x'] += offset['x']
point['y'] += offset['y']
print(point)
return modified_points
polyline = [
{'x': 0,'y': 0},
{'x': 10, 'y': 10},
'{"x": 20, "y": 20}',
{'x': 30, 'y': 30}
]
results = shift({'x': 10, 'y': -5}, polyline)
print(results)
The error goes as following:
File "/home/selby/PycharmProjects/10thPractical/3rd.py", line 37, in <module>
results = shift({'x': 10, 'y': -5}, polyline)
File "/home/selby/PycharmProjects/10thPractical/3rd.py", line 19, in shift
point['x'] += offset['x']
TypeError: string indices must be integers
Process finished with exit code 1
You do not store the return value when you call parse(point), i.e. point is still a string when you try to use it in point['x'] += offset['x'] (as the error indicates).
Replace the line with point = parse(point), and the error will disappear.

key error: 'x' --> adding key value pair in for loop, key being char

I am a beginner in python and I am trying to solve a coding problem, got this error. Don't understand why ? I went through a couple of Q/A's here but they don't seem to solve my problem. Essentially what I am trying to do is iterate over a string, through its characters and fill these characters in a dictionary. With characters being the keys and values being the number of times these characters appeared. So I'm trying the following:
def myfunc(mystring):
for i in mystring:
if charCounter[i]:
charCounter[i] += 1
charCounter[i] = 1
mystring = "hello! how are you ?"
myfunc(mystring)
and Im getting following error:
File "xyq.py", line 3, in myfunc
if CharCounter[i]:
KeyError: 'h'
Can someone please suggest, where am I going wrong ? And if possible how can I improve the code ?
Thanks
You need to check if i is in charCounter before you try to retrieve it:
if i in charCounter:
charCounter[i] += 1
else:
charCounter[i] = 1
Or alternatively:
if charCounter.get(i):
...
if charCounter[i]:
throws KeyError if the key does not exist. What you want to do isuse if i in charCounter: instead:
if i in char_counter:
char_counter[i] += 1
else:
char_counter[i] = 1
Alternatively you could use get which gets the value if it exists, or returns the second (optional) value if it didn't exist:
char_counter[i] = char_counter.get(i, 0) + 1
However this counting pattern is so popular that a whole class exists for it: collections.Counter:
from collections import Counter
def my_func(my_string):
return Counter(my_string)
Example:
>>> counts = my_func('hello! how are you ?')
>>> counts
Counter({' ': 4, 'o': 3, 'h': 2, 'l': 2, 'e': 2, '!': 1, 'r': 1, 'a': 1,
'?': 1, 'w': 1, 'u': 1, 'y': 1})
>>> counts[' ']
4
collections.Counter is a subclass of dictionary, so it would behave in the same way that an ordinary dictionary would do with item access and so forth.

Converting CNC drillings from old to new system (using Python)

I have this kind of file (part):
H DX=615 DY=425 DZ=22.15 -AB C=0 T=0 R=999 *MM /"def" BX=2.5 BY=452.5 BZ=25 ;M20150710.
XBO X=100 Y=50 Z=5 V=1000 R=0 x=0 y=0 D=10 N="P" F=1 ;Test F1/10P.
...
which I want to convert to a new programming system. What I want to do is first read the header (H) and put the DX, DY and DZ values in respectively named variables. I managed to do this, but when I came to process my XBO line (a drilling, from which I need X, Y, Z, V, R, x, y, D, N, F and ;, also in separate variables) my code started looking very ugly very fast.
So I started over, and came up with this:
f = open("input.xxl") # open input file
for line in f:
if Debug==1: print line
for char in line:
charbuffr=charbuffr+char
if "H" in charbuffr:
if Debug==1: print'HEADER found!'
charbuffr=""
if "XBO" in charbuffr:
if Debug==1: print'XBO found!'
charbuffr=""
This correctly identifies the separate commands H and XBO, but I'm kind of stuck now. I can use the same method to extract all the variables, from loops inside the H and XBO loops, but this does not seem like good coding...
Can anyone set me on the right foot please? I don't want a full solution, as I love coding (well my main job is coding for CNC machines, which seems easy now compared to Python), but would love to know which approach is best...
Instead of converting data types by hand, you could use ast. literal_eval. This helper function takes a list of the form ['a=2', 'b="abc"'] and converts into a dictionary {'a': 2, 'b': 'abc'}:
import ast
def dict_from_row(row):
"""Convert a list of strings in the form 'name=value' into a dict."""
res = []
for entry in row:
name, value = entry.split('=')
res.append('"{name}": {value}'.format(name=name, value=value))
dict_string = '{{{}}}'.format(', '.join(res))
return ast.literal_eval(dict_string)
Now parsing the file becomes a bit simpler:
for line in f:
row = line.split()
if not row:
continue
if row[0] == 'H':
header = dict_from_row(row[1:4])
elif line[0] == 'XBO':
xbo = dict_from_row(row[1:11])
Results:
>>> header
{'DX': 615, 'DY': 425, 'DZ': 22.15}
>>> xbo
{'D': 10, 'F': 1, 'R': 0, 'V': 1000, 'X': 100, 'Y': 50, 'Z': 5, 'x': 0, 'y': 0}
As an inspiration, you can do something like this:
for raw_line in f:
line = raw_line.split()
if not line:
continue
if line[0] == 'H':
header = {}
for entry in line[1:4]:
name, value = entry.split('=')
header[name] = float(value)
elif line[0] == 'XBO':
xbo = {}
for entry in line[1:11]:
name, value = entry.split('=')
try:
xbo[name] = int(value)
except ValueError:
xbo[name] = value[1:-1] # stripping of the ""
Now headercontains the extensions of your domain:
{'DX': 615.0, 'DY': 425.0, 'DZ': 22.15}
and xbo the other values:
{'D': 10,
'F': 1,
'N': 'P',
'R': 0,
'V': 1000,
'X': 100,
'Y': 50,
'Z': 5,
'x': 0,
'y': 0}
Access the individual values in the dictionaries:
>>> header['DX']
615.0

my str(float) gets broken on histogram dictionary conversion, how do I stop this?

When attempting to histogram a list of numbers(in str formats) all of my numbers get broken up
for instance
a = ['1','1.5','2.5']
after running my histogram function
my dictionary looks like
{'1': 2, '2': 1, '5': 2, '.': 2}
my histogram function is
def histogram(a):
d = dict()
for c in a:
d[c] = d.get(c,0)+1
return d
I'm doing a project for school and have everything coded in, but when I get to doing the mode portion and I use numbers that aren't specifically int I get the above returns
How can I adjust/change this so it accepts the strings exactly as typed
Python 2.7 on Windows 7x64
You can convert each string element to a float before passing it your histogram function.
a = ['1','1.5','2.5']
a = [float(i) for i in a]
def histogram(a):
d = dict()
for c in a:
d[c] = d.get(c,0)+1
return d
print histogram(a)
There might be an error in your list definition. Running your code I get
{'1': 1, '1.5': 1, '2.5': 1}
If I change the definition of a from
a = ['1','1.5','2.5']
to
a = '1' '1.5' '2.5'
I get the output you showed us.
So please double check how your list is defined.
You can use something like this:
>>> a = ['1','1.5','2.5']
>>> dict.fromkeys(a, 0)
{'1': 0, '1.5': 0, '2.5': 0}
Now you can iterate over keys to set the corresponding value.
I have used the following dict comprehension to reduce my work.
>>> {key: float(key)+1 for key in a}
{'1': 2.0, '1.5': 2.5, '2.5': 3.5}
enjoy :)
The histgram function does work as it's written. If however you you inadvertently .join() your list your histogram with then histogram the resulting object. For instance... t = ['1.0','2.0','2.5'] and
s = s.join(t) s will then be == '1.02.02.5' and histogram(s) will count the decimals as values in the slice. My problem was that I had placed a .join() prior to calling histogram.
My appologies to anyone that wasted any real time on this.

Testing all Letters?

I am working on a script and the script should read a text file and test to see if the specified letters(a,a,r,d,v,a,r,k) are on each line. Im having a problem as I am trying to check for 3 different a's instead of just one. My code is below:
#Variables
advk = ['a','a','r','d','v','a','r','k']
textfile = []
number = 0
life = 0
for line in open('input.txt', 'rU'):
textfile.append(line.rstrip().lower())
while life == 0:
if all(word in textfile[number] for word in advk):
printed = number + 1
print ("Aardvark on line " + str(printed))
number+=1
if number == len(textfile):
life+=1
else:
number+=1
Everytime you want to count something in python, keep the Counter class in mind.
from collections import Counter
advk = Counter(['a','a','r','d','v','a','r','k'])
with open('input.txt', 'rU') as file:
for i, line in enumerate(file.readlines()):
if not advk - Counter(line.lower()):
print ("Aardvark on line " + str(i+1))
Given the input line
dffdaardvarksdsda
the Counter would look like these
Counter({'d': 5, 'a': 4, 'f': 2, 's': 2, 'r': 2, 'k': 1, 'v': 1})
and
Counter({'a': 3, 'r': 2, 'd': 1, 'k': 1, 'v': 1})
for your list of letters to search.
We use a trick by simply substracting the two Counters advl - Counter(line.lower()) and check if the resulting Counter has no elements left.
Other things to note:
You can use the with statement to ensure your file gets closed.
You can use enumerate instead counting the line numbers.
if advk list is variable and contents are read from somewhere else then to maintain unique elements in the list you can convert it to set and check.
advk = ['a','a','r','d','v','a','r','k']
advk = list(set(advk))
This makes advk a unique list and avoids check multiple 'a's in the line.
# If the line "ardvrk" should match, this is a solution:
chars=set('aardvark')
for nr, line in enumerate(open('input.txt', 'rU')):
if not chars-set(line): # is subset?
print 'match', nr, line,

Categories