This question already has answers here:
Python: most idiomatic way to convert None to empty string?
(17 answers)
Closed 3 years ago.
I'm trying to make a templated string that will print values of a given dict. However, the key may or may not exist in the dict. If it doesn't exist, I'd like it to return an empty string instead.
To demonstrate what I mean, let's say I have a dict:
test_dict = { 1: "a", 2: "b"}
And a template string:
'{} {} {}'.format(test_dict.get(1), test_dict.get(2), test_dict.get(3))
I'd like the following output:
'a b '
But instead I get:
'a b None'
Use the dictionary's get function. This allows you to specify a value to return if the key is not found
'{}, {}, {}'.format(test_dict.get(1,''), test_dict.get(2,''), test_dict.get(3, ''))
One way would be to get the length of the dict, and put the same amount of placeholeders inside the template:
In [27]: test_dict = { 1: "a", 2: "b"}
In [28]: ' '.join(['{}'] * len(test_dict))
Out[28]: '{} {}'
In [29]: ' '.join(['{}'] * len(test_dict)).format(*test_dict.values())
Out[29]: 'a b'
Note that, this is basically the same as ' '.join(test_dict.values()) but showing you the template string as an example.
UPDATES PER OP COMMENT
You can use the string library to help here. See the below script using your test_dict:
#https://stackoverflow.com/a/51359690
from string import Formatter
class NoneAsEmptyFormatter(Formatter):
def get_value(self, key, args, kwargs):
v = super().get_value(key, args, kwargs)
return ' ' if v is None else v
fmt = NoneAsEmptyFormatter()
test_dict = { 1: "a", 2: "b"}
test_str = fmt.format('{} {} {}', test_dict.get(1), test_dict.get(2), test_dict.get(3))
print(test_str)
We build a quick NoneAsEmptyFormatter class and use that to format the strings in coming from the dict.
Re your comment,
Now that you mention the extra space though, is there a way to remove the placeholder completely if key doesn't exist?
Yes, this is possible. Just make a list of values, filter out any Nones, then join the result:
In [3]: values = map(test_dict.get, [1, 2, 3])
In [4]: ' '.join(v for v in values if v is not None)
Out[4]: 'a b'
Or if order is not important, or if you're using Python 3.7+ and you want to preserve insertion order, you can skip some steps:
In [5]: ' '.join(test_dict.values())
Out[5]: 'a b'
Related
How do I concatenate a list of strings into a single string?
For example, given ['this', 'is', 'a', 'sentence'], how do I get "this-is-a-sentence"?
For handling a few strings in separate variables, see How do I append one string to another in Python?.
For the opposite process - creating a list from a string - see How do I split a string into a list of characters? or How do I split a string into a list of words? as appropriate.
Use str.join:
>>> words = ['this', 'is', 'a', 'sentence']
>>> '-'.join(words)
'this-is-a-sentence'
>>> ' '.join(words)
'this is a sentence'
A more generic way (covering also lists of numbers) to convert a list to a string would be:
>>> my_lst = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> my_lst_str = ''.join(map(str, my_lst))
>>> print(my_lst_str)
12345678910
It's very useful for beginners to know
why join is a string method.
It's very strange at the beginning, but very useful after this.
The result of join is always a string, but the object to be joined can be of many types (generators, list, tuples, etc).
.join is faster because it allocates memory only once. Better than classical concatenation (see, extended explanation).
Once you learn it, it's very comfortable and you can do tricks like this to add parentheses.
>>> ",".join("12345").join(("(",")"))
Out:
'(1,2,3,4,5)'
>>> list = ["(",")"]
>>> ",".join("12345").join(list)
Out:
'(1,2,3,4,5)'
Edit from the future: Please don't use the answer below. This function was removed in Python 3 and Python 2 is dead. Even if you are still using Python 2 you should write Python 3 ready code to make the inevitable upgrade easier.
Although #Burhan Khalid's answer is good, I think it's more understandable like this:
from str import join
sentence = ['this','is','a','sentence']
join(sentence, "-")
The second argument to join() is optional and defaults to " ".
list_abc = ['aaa', 'bbb', 'ccc']
string = ''.join(list_abc)
print(string)
>>> aaabbbccc
string = ','.join(list_abc)
print(string)
>>> aaa,bbb,ccc
string = '-'.join(list_abc)
print(string)
>>> aaa-bbb-ccc
string = '\n'.join(list_abc)
print(string)
>>> aaa
>>> bbb
>>> ccc
We can also use Python's reduce function:
from functools import reduce
sentence = ['this','is','a','sentence']
out_str = str(reduce(lambda x,y: x+"-"+y, sentence))
print(out_str)
We can specify how we join the string. Instead of '-', we can use ' ':
sentence = ['this','is','a','sentence']
s=(" ".join(sentence))
print(s)
If you have a mixed content list and want to stringify it, here is one way:
Consider this list:
>>> aa
[None, 10, 'hello']
Convert it to string:
>>> st = ', '.join(map(str, map(lambda x: f'"{x}"' if isinstance(x, str) else x, aa)))
>>> st = '[' + st + ']'
>>> st
'[None, 10, "hello"]'
If required, convert back to the list:
>>> ast.literal_eval(st)
[None, 10, 'hello']
If you want to generate a string of strings separated by commas in final result, you can use something like this:
sentence = ['this','is','a','sentence']
sentences_strings = "'" + "','".join(sentence) + "'"
print (sentences_strings) # you will get "'this','is','a','sentence'"
def eggs(someParameter):
del spam[3]
someParameter.insert(3, ' and cats.')
spam = ['apples', 'bananas', 'tofu', 'cats']
eggs(spam)
spam =(','.join(spam))
print(spam)
Without .join() method you can use this method:
my_list=["this","is","a","sentence"]
concenated_string=""
for string in range(len(my_list)):
if string == len(my_list)-1:
concenated_string+=my_list[string]
else:
concenated_string+=f'{my_list[string]}-'
print([concenated_string])
>>> ['this-is-a-sentence']
So, range based for loop in this example , when the python reach the last word of your list, it should'nt add "-" to your concenated_string. If its not last word of your string always append "-" string to your concenated_string variable.
This question already has answers here:
Python: Removing spaces from list objects [duplicate]
(7 answers)
Remove all whitespace in a string
(14 answers)
Closed 3 years ago.
So I have something like:
d = {'d':[' Cool Guy', ' Cool Gal']}
How do I remove the space inside the key-value so my output would be
d = {'d':['Cool Guy', 'Cool Gal']}
I appreciate the help, thank you.
d = {'d':[' Cool Guy', ' Cool Gal']}
for key in d:
d[key] = [ls.strip() for ls in d[key]]
d = {'d':[' Cool Guy', ' Cool Gal']}
for k, v in d.items():
new_d = {k:[elem[1:] for elem in v]}
print(new_d)
Output:
{'d': ['Cool Guy', 'Cool Gal']}
Logic:
Extract the key (k) and corresponding value list (v).
Loop through its items and ignore first character to form new array.
Store new list as the new value of the dictionary.
I have a list of strings that looks, like this:
myList = [
"this 1 is my string",
"a nice 2 string",
"string is 3 so nice"
]
I'd like to convert this string into a dict that also looks, like this:
{
"1": "this is my string",
"2": "a nice string",
"3": "string is so nice"
}
I don't know how to do this.
Only the integer can become the key but everything else must become the value, thank you.
import re
myDict = {}
for element in myList:
# Find number using regex.
key = re.findall(r'\d+', element)[0]
# Get index of number.
index = element.index(key)
# Create new string with index and trailing space removed.
new_element = element[:index] + element[index + 2:]
# Add to dict.
myDict[key] = new_element
If you multiple numbers in a line, it will take the first number as the key for the dict,
>>> for line in myList:
... match = re.search(r'\d+',line)
... if match:
... num = match.group()
... newline = line.partition(num) # control over the partition
... newline = newline[0].strip() + ' '.join(newline[2:])
... d[num] = newline
...
>>>
>>> d
{'1': 'this is my string', '3': 'string is so nice', '2': 'a nice string'}
The simplest way to do this without installing any external dependencies is by using the findall method from the re module.
from re import findall
def list_to_dict(lst):
result = {}
for value in lst:
match = findall(r"\d", value)
if len(match) > 0:
result[match[0]] = value.replace(match[0], "").replace(" ", " ")
return result
If you wanted to, you could replace the 0 index with another index, although you should only do this if you are certain you know where the integer's index is.
Then using your list:
my_list = [
"this 1 is my string",
"a nice 2 string",
"string is 3 so nice"
]
You'd call the function, like this:
print(list_to_dict(my_list))
Which should output this dict:
{'1': 'this is my string', '2': 'a nice string', '3': 'string is so nice'}
Good luck.
i am trying out a function where you have to use def function(a,b,c,d)
a is a string so i did
a = str(a)
b is an integer so i did
b= int(b)
c is also a string;
c = str(c)
and d is a boolean (all i know about boolean is True or False); so
d = True
i wanted to change the order of the elements into
[c,a,b,d]
and i assigned this to result = [c,a,b,d]
when i used the return function
return str(result), (because i want to return a string)
i ended up with
"[ 'c', 'a', b, d]"
i have tried everything to get rid of the ' ' and also the spacing because it should really look like
'[c,a,b,d]'
what can i do to remove it?
def elem(tree,year,ident,passed):
tree = str(tree)
year = int(year)
ident = str(ident)
passed = True
result = [ident,tree,year,passed]
return str(result)
this is what i;ve done so far
so if i wanted to test the code i have so far in the python shell i end up with
>>> elem("pine",2013,"1357",True)
"['1357', 'pine', 2013, True]"
the output that i want from this is
'[1357,pine,2013,True]'
sorry if i didn't provide enough. this is all i have right now.. and sorry for not doing good formatting for the posting..
Just create the string you want from the data structure you have:
>>> '[{},{},{},{}]'.format('c','a',2,True)
'[c,a,2,True]'
>>> '[{},{},{},{}]'.format(*['c','a',2,True])
'[c,a,2,True]'
>>> '[{},{},{},{}]'.format(*['1357', 'pine', 2013, True])
'[1357,pine,2013,True]'
Or edit the string representation of a data structure to be what you want it to be:
>>> str(['c', 'a', 2, True])
"['c', 'a', 2, True]"
>>> str(['c', 'a', 2, True]).replace("'","").replace(' ','')
'[c,a,2,True]'
In either case, the final outer ' go away when you print the string:
>>> print('[{},{},{},{}]'.format(*['c','a',2,True]))
[c,a,2,True]
>>> print(str(['c', 'a', 2, True]).replace("'","").replace(' ',''))
[c,a,2,True]
>>> li=['1357', 'pine', 2013, True]
>>> print('[{},{},{},{}]'.format(*li))
[1357,pine,2013,True]
The reason you have " " is because it's a string. You returned the string representation of the list, when infact you should just be returning the list:
return result
With the string you have, you can safely convert it back to a list with ast.literal_eval:
import ast
...
myresult = function(a, b, c, d)
print ast.literal_eval(myresult)
return "[" + ",".join(result) + "]"
When you call str(result) it gives a string representation of the object result. What that string actually looks like depends on the implementation of the class that the object belongs to (it calls the special method __str__ in the class to do the conversion).
Since the object (result) belongs to class list then you get the standard string representation for a list. You cannot (sensibly) change the list class, so you need to create a different representation.
In your sample code, I'm puzzled why you are doing the conversions. Why convert year to an int when you want a string representation? Why set passed to True when it is a parameter? Anyway:
def elem(tree, year, ident, passed):
passed = True
result = "[%s,%s,%d,%s]" % (ident, tree, year, passed)
return result
print(elem("pine", 2013, "1357", True))
Gives:
[1357,pine,2013,True]
I have a string s (note that the a and b are not enclosed in quotation marks, so it can't directly be evaluated as a dict):
s = '{a:1,b:2}'
I want convert this variable to a dict like this:
{'a':1,'b':2}
How can I do this?
This will work with your example:
import ast
def elem_splitter(s):
return s.split(':',1)
s = '{a:1,b:2}'
s_no_braces = s.strip()[1:-1] #s.translate(None,'{}') is more elegant, but can fail if you can have strings with '{' or '}' enclosed.
elements = (elem_splitter(ss) for ss in s_no_braces.split(','))
d = dict((k,ast.literal_eval(v)) for k,v in elements)
Note that this will fail if you have a string formatted as:
'{s:"foo,bar",ss:2}' #comma in string is a problem for this algorithm
or:
'{s,ss:1,v:2}'
but it will pass a string like:
'{s ss:1,v:2}' #{"s ss":1, "v":2}
You may also want to modify elem_splitter slightly, depending on your needs:
def elem_splitter(s):
k,v = s.split(':',1)
return k.strip(),v # maybe `v.strip() also?`
*Somebody else might cook up a better example using more of the ast module, but I don't know it's internals very well, so I doubt I'll have time to make that answer.
As your string is malformed as both json and Python dict so you neither can use json.loads not ast.literal_eval to directly convert the data.
In this particular case, you would have to manually translate it to a Python dictionary by having knowledge of the input data
>>> foo = '{a:1,b:2}'
>>> dict(e.split(":") for e in foo.translate(None,"{}").split(","))
{'a': '1', 'b': '2'}
As Updated by Tim, and my short-sightedness I missed the fact that the values should be integer, here is an alternate implementation
>>> {k: int(v) for e in foo.translate(None,"{}").split(",")
for k, v in [e.split(":")]}
{'a': 1, 'b': 2}
import re,ast
regex = re.compile('([a-z])')
ast.literal_eval(regex.sub(r'"\1"', s))
out:
{'a': 1, 'b': 2}
EDIT:
If you happen to have something like {foo1:1,bar:2} add an additional capture group to the regex:
regex = re.compile('(\w+)(:)')
ast.literal_eval(regex.sub(r'"\1"\2', s))
You can do it simply with this:
s = "{a:1,b:2}"
content = s[s.index("{")+1:s.index("}")]
to_int = lambda x: int(x) if x.isdigit() else x
d = dict((to_int(i) for i in pair.split(":", 1)) for pair in content.split(","))
For simplicity I've omitted exception handling if the string doesn't contain a valid specification, and also this version doesn't strip whitespace, which you may want. If the interpretation you prefer is that the key is always a string and the value is always an int, then it's even easier:
s = "{a:1,b:2}"
content = s[s.index("{")+1:s.index("}")]
d = dict((int(pair[0]), pair[1].strip()) for pair in content.split(","))
As a bonus, this version also strips whitespace from the key to show how simple it is.
import simplejson
s = '{a:1,b:2}'
a = simplejson.loads(s)
print a