I have a text box in wxPython that takes the output of dictionary.items() and displays it to the user as items are added to the dictionary. However, the raw data is very ugly, looking like
[(u'BC',45)
(u'CHM',25)
(u'CPM',30)]
I know dictionary.items() is a list of tuples, but I can't seem to figure out how to make a nice format that is also compatible with the SetValue() method of wxPython.
I've tried iterating through the list and tuples. If I use a print statement, the output is fine. But when I replace the print statement with SetValue(), it only seems to get the last value of each tuple, rather than both items in the tuple.
I've also tried creating a string and passing that string to SetValue() but, again, I can only get one item in the tuple or the other, not both.
Any suggestions?
Edit: Yes, I am passing the results of the dictionary.items() to a text field in a wxPython application. Rather than having the results like above, I'm simply looking for something like:
BC 45
CHM 25
CMP 30
Nothing special, just simply pulling each value from each tuple and making a visual list.
I have tried making a string format and passing that to SetValue() but it gets hung up on the two values in the tuple. It will either double print each string and add the integers together or it simply returns the integer, depending on how I format it.
There is no built-in dictionary method that would return your desired result.
You can, however, achieve your goal by creating a helper function that will format the dictionary, e.g.:
def getNiceDictRepr(aDict):
return '\n'.join('%s %s' % t for t in aDict.iteritems())
This will produce your exact desired output:
>>> myDict = dict([(u'BC',45), (u'CHM',25), (u'CPM',30)])
>>> print getNiceDictRepr(myDict)
BC 45
CHM 25
CPM 30
Then, in your application code, you can use it by passing it to SetValue:
self.textCtrl.SetValue(getNiceDictRepr(myDict))
Maybe the pretty print module will help:
>>> import pprint
>>> pprint.pformat({ "my key": "my value"})
"{'my key': 'my value'}"
>>>
text_for_display = '\n'.join(item + u' ' + unicode(value) for item, value in my_dictionary.items())
use % formatting (known in C as sprintf), e.g:
"%10s - %d" % dict.items()[0]
Number of % conversion specifications in the format string should match tuple length, in the dict.items() case, 2. The result of the string formatting operator is a string, so that using it as an argument to SetValue() is no problem. To translate the whole dict to a string:
'\n'.join(("%10s - %d" % t) for t in dict.items())
The format conversion types are specified in the doc.
That data seems much better displayed as a Table/Grid.
I figured out a "better" way of formatting the output. As usual, I was trying to nuke it out when a more elegant method will do.
for key, value in sorted(self.dict.items()):
self.current_list.WriteText(key + " " + str(self.dict[key]) + "\n")
This way also sorts the dictionary alphabetically, which is a big help when identifying items that have already been selected or used.
Related
I'd like to take some numbers that are in a string in python, round them to 2 decimal spots in place and return them. So for example if there is:
"The values in this string are 245.783634 and the other value is: 25.21694"
I'd like to have the string read:
"The values in this string are 245.78 and the other value is: 25.22"
What you'd have to do is find the numbers, round them, then replace them. You can use regular expressions to find them, and if we use re.sub(), it can take a function as its "replacement" argument, which can do the rounding:
import re
s = "The values in this string are 245.783634 and the other value is: 25.21694"
n = 2
result = re.sub(r'\d+\.\d+', lambda m: format(float(m.group(0)), f'.{n}f'), s)
Output:
The values in this string are 245.78 and the other value is: 25.22
Here I'm using the most basic regex and rounding code I could think of. You can vary it to fit your needs, for example check if the numbers have a sign (regex: [-+]?) and/or use something like the decimal module for handling large numbers better.
Another alternative using regex for what it is worth:
import re
def rounder(string, decimal_points):
fmt = f".{decimal_points}f"
return re.sub(r'\d+\.\d+', lambda x: f"{float(x.group()):{fmt}}", string)
text = "The values in this string are 245.783634 and the other value is: 25.21694"
print(rounder(text, 2))
Output:
The values in this string are 245.78 and the other value is: 25.22
I'm not sure quite what you are trying to do. "Round them in place and return them" -- do you need the values saved as variables that you will use later? If so, you might look into using a regular expression (as noted above) to extract the numbers from your string and assign them to variables.
But if you just want to be able to format numbers on-the-fly, have you looked at f-strings? f-string
print(f"The values in this string are {245.783634:.2f} and the other value is: {25.21694:.2f}.")
output:
The values in this string are 245.78 and the other value is: 25.22.
You can use format strings simply
link=f'{23.02313:.2f}'
print(link)
This is one hacky way but many other solutions do exist. I did that in one of my recent projects.
I'm trying to get this string into list, how can i do that pleas ?
My string :
x = "[(['xyz1'], 'COM95'), (['xyz2'], 'COM96'), (['xyz3'], 'COM97'), (['xyz4'], 'COM98'), (['xyz5'], 'COM99'), (['xyz6'], 'COM100')]"
I want to convert it to a list, so that:
print(list[0])
Output : (['xyz1'], 'COM95')
If you have this string instead of a list, that presumes it is coming from somewhere outside your control (otherwise you'd just make a proper list). If the string is coming from a source outside your program eval() is dangerous. It will gladly run any code passed to it. In this case you can use ast.liter_eval() which is safer (but make sure you understand the warning on the docs):
import ast
x = "[(['xyz1'], 'COM95'), (['xyz2'], 'COM96'), (['xyz3'], 'COM97'), (['xyz4'], 'COM98'), (['xyz5'], 'COM99'), (['xyz6'], 'COM100')]"
l = ast.literal_eval(x)
Which gives an l of:
[(['xyz1'], 'COM95'),
(['xyz2'], 'COM96'),
(['xyz3'], 'COM97'),
(['xyz4'], 'COM98'),
(['xyz5'], 'COM99'),
(['xyz6'], 'COM100')]
If the structure is uniformly a list of tuples with a one-element list of strings and an individual string, you can manually parse it using the single quote as a separator. This will give you one string value every other component of the split (which you can access using a striding subscript). You can then build the actual tuple from pairing of two values:
tuples = [([a],s) for a,s in zip(*[iter(x.split("'")[1::2])]*2)]
print(tuples[0])
(['xyz1'], 'COM95')
Note that this does not cover the case where an individual string contains a single quote that needed escaping
You mean convert list like string into list? Maybe you can use eval().
For example
a="[1,2,3,4]"
a=eval(a)
Then a become a list
to convert as list use x = eval(x)
print(list[0]) will give you an error because list is a python builtin function
you should do print(x[0]) to get what you want
i run this formating code print("%15s%.2f"%((heights[j])),end="") but i have this error what is the wrong here ??
TypeError: not enough arguments for format string
What does your heights looks like?
Here is a working example
heights = [("test",3.14)]
print("%15s%.2f"%((heights[0])),end="")
So heights must be a list of tuples or lists with 2 elements.
the first % formats the first value into the string and the second % formats the second value. The problem is you only have one value to format into the string (unless heights[j] is a list or tuple.
if you want heights[j to be formatted in both places, i suggest doing something like this:
print("{0}15s{0}.2f".format(heights[j]), end="")
this will replace every {0} in the string with the first argument passed to format()
I created subdataframes out of a big dataframe in a loop, and I've been trying to create a column on those subdataframes, inside the loop:
Partidas=data2['Partida'].unique()
Partida2=[w.replace(' ','_') for w in Partidas]
for i, j in zip(Partidas,Partida2):
globals()['%s' % j]=data2.loc[data2['Partida']==i]
for k in globals().items()
['%s' % k]['Top 10']='a'
So I create one dataframe for every 'Partida' and their name is the name of the 'Partida' they represent. Now I want to add a column to those dataframes called 'Top 10', but I get the following error:
TypeError: not all arguments converted during string formatting
Do you know if there's a way I could add that column inside the loop, without having to go dataframe per dataframe adding the column?
Thanks in advance!
The proximate problem is that '%s' % k is not quite the same thing as str(k) but slower—it's:
The same thing as str(k) but slower if k is anything but a tuple,
The same thing as str(k[0]) if k is a one-element tuple, or
A TypeError if k is a tuple with any other length.
The % operator takes a tuple, but for compatibility with Python ancient 1.2 or so, and for quick&dirty hacking at the interactive terminal, it treats anything that isn't a tuple as a one-element tuple. Which works, except when you actually give it a tuple.
If you don't understand why k is a tuple—that's exactly what dict.items() iterates: key-value tuples.
To fix this, you can use '%s' % (k,). This actually is the same thing as str(k) but slower.
But why do you want the same thing as str(k) but slower in the first place? Why not just str(k)?
But then it's not clear why you're trying to do this in the first place, and all it's going to do is give you another TypeError.
[str(item)] is a list of one string. (The string happens to be a string representation of a key-value tuple out of globals(), but that doesn't actually matter here.) You then try to index that list with 'Top 10', which obviously isn't an index.
If that error isn't obvious, imagine that you'd written this instead:
lst = [1, 2, 3]
lst['Top 10'] = 'a'
Maybe what you wanted is:
for k in globals().values():
k['Top 10'] = 'a'
But that isn't going to work either. There are a few more problems to get through, but ultimately you come down to one that can't be solved.
globals() contains all of your globals, not just the ones you created above.
For example, it contains Partidas, and k, and probably pd. And a bunch of other modules you imported and functions you defined and so on. Most of those things are not dicts, dataframes, or other kinds of mappings, so you're just going to get yet another TypeError. Worse, a few of them are mappings, but not mappings you wanted to add a 'Top 10' key to, and for those, you'll be corrupting your data silently, instead of getting an error.
All of this just demonstrates why you don't want to create a whole bunch of global variables in the first place. If you'd, say, just created one global dict, and stored everything in that, this would all be easy.
Something like this:
stuff = {}
for i, j in zip(Partidas,Partida2):
stuff[j] = data2.loc[data2['Partida']==i]
for k in stuff.values():
k['Top 10'] = 'a'
I am trying to use the Abaqus (a commercial FEA code) scripting interface to generate FE models, although my question is relating to Python specifically, but a bit of background on why I am trying to do this.
Abaqus has a built in boolean merge operation that requires the following syntax to be used:
a.InstanceFromBooleanMerge(name='name_string', instances=(
a.instances['string1'], a.instances['string2'],
a.instances['string3'], ), originalInstances=SUPPRESS,
domain=GEOMETRY)
The 'instances' parameter is specified as a tuple where each element is of the format
a.instances['string1']
I am trying to make it so that the number of elements within this tuple, and obviously the names within it are scriptable. Currently I have code which looks like:
my_list = []
for i in range(4):
name = str('a.instances[\'')+str('name_')+str(i)+str('\']')
my_list.append(name)
my_list = tuple(my_list)
print my_list
However, this gives:
("a.instances['name_0']", "a.instances['name_1']", "a.instances['name_2']",
a.instances['name_3']")
I have tried using lstrip and rstrip to remove the " characters but to no avail. Is there a way of generating a tuple of arbitrary length where the elements are not enclosed in inverted commas? The format is specified by the Abaqus interface, so there is no alternative format that can be used.
Many Thanks
You're close, try:
for i in range(4):
val = a.instances["name_"+str(i)]
my_list.append(val)
You can make this even shorter using a generator expression:
my_list = tuple(a.instances["name_"+str(i)] for i in range(4))
Those characters will be printed out simply because you're printing out a tuple - that means strings will be quoted, so you can see the difference between (123,) and ("123",). If you want to have it without quotes, construct the output yourself:
def make_tuple_of(n):
return '(' + ', '.join("a.instances['name_" + str(i) + "']" for i in range(n)) + ')'
Edit: I thought you actually wanted to generate the code itself, not create tuple in the current code. If generating a tuple in current code is what you actually want to do, just use tuple(a.instances['name_' + str(i)] for i in range(n))
Edit2: Actually, you could check the library you're working with. Unless it specifically tests for tuples for some reason, it accept lists just fine, since the interface for both is pretty much the same. If it does, you could just pass it [a.instances['name_' + str(i)] for i in range(n)] as a parameter and be done.