I've found tons of solutions doing exactly what I'm trying to do WITHOUT lambda...but I'm learning lambda today...
I have a string stri
and I'm trying to replace some characters in stri
that are all stored in a dictionary.
bad_chars={"\newline":" ","\n": " ", "\b":" ", "\f":" ", "\r":" ", "\t":" ", "\v":" ", "\0x00":" "}
and then I want to print stri
out all pretty and empty of all of these ugly characters. My current code print's stri
many many times.
format_ugly = lambda stri: [ stri.replace(i,j) for i,j in bad_chars.iteritems()]
Is there a way to make it print开发者_JAVA百科 once, and with only 1 lambda function?
If you really want to you can force a lambda function into it:
print ''.join(map(lambda x: bad_chars.get(x, x), stri))
But really there's absolutely no need to use a lambda function here. All you need is:
print ''.join(bad_chars.get(x, x) for x in stri)
This solution is also linear time (ie O(n)) whereas all the other solutions are potentially quadratic as they involve scanning the entire string to replace each value O(n*m) where m is the size of the bad_chars
dict.
Example:
bad_chars= {"\newline":" ","\n": " ", "\b":" ", "\f":" ", "\r":" ", "\t":" ", "\v":" ", "\0x00":" "}
stri = "a \b string\n with \t lots of \v bad chars"
print ''.join(bad_chars.get(x, x) for x in stri)
Ouptut:
a string with lots of bad chars
You can't really do it that easily and if you could a lambda
function is still not designed for your use case.
Multiple replacements like that are done using a regular for
loop statement, and a lambda
is limited to a single expression. If you have to use a function, use a normal function – it's entirely equivalent to a lambda function except that it's not limited to a single expression.
If you really must know how to do it in a single expression, you have three choices:
1) If you use unicode
strings (or Python 3), and limit your bad substrings to single characters (i.e. remove "\newline"
), you can use the unicode.translate
method.
bad_chars = {u"\n": u" ", u"\b": u" ", u"\f": u" ", u"\r": u" ", u"\t": u" ", u"\v": u" ", u"\x00": u" "}
bad_chars_table = dict((ord(k), v) for k, v in bad_chars.iteritems())
translator = lambda s: s.translate(bad_chars_table)
print translator(u"here\nwe\tgo")
2) Use regular expressions:
translator = lambda s: re.sub(r'[\n\b\f\r\t\v\x00]', ' ', s)
3) You can use reduce
which can be used to reduce a sequence using a binary operation, essentially repeatedly calling a function of two arguments with the current value and an element of the sequence to get the next value.
translator = lambda s: reduce(lambda x, (from, to): x.replace(from, to), bad_chars.iteritems(), s)
As you can see, the last solution is much more difficult to understand than:
def translator(s):
for original, replacement in bad_chars.iteritems():
s = s.replace(original, replacement)
return s
And both solutions do the same thing. It's often better to program for the end, not for the means. For an arbitrary problem a comprehensible single-expression solution wouldn't exist at all.
You shouldn't produce a list of the values. Your code produces a list of values with the original text with only one character replaced (one per version). Instead operate on the result of one entry and pass it for the next. This is pretty much what reduce does:
replaced = reduce(lambda stri, r: stri.replace(r[0], r[1]), bad_chars.iteritems(), original)
this is roughly equivalent to:
stri.replace(r0[0], r0[1]).replace(r1[0], r1[1]).replace(...)
where r0..rn
are the values from bad_chars.iteritems()
.
精彩评论